@glasstrace/sdk 1.1.0 → 1.1.2
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/README.md +78 -1
- package/dist/{chunk-55FBXXER.js → chunk-2M57EO6U.js} +2 -2
- package/dist/chunk-3LILTM3T.js +384 -0
- package/dist/chunk-3LILTM3T.js.map +1 -0
- package/dist/{chunk-KE7MCPO5.js → chunk-4EZ6JTDG.js} +2 -2
- package/dist/{chunk-67RIOAXV.js → chunk-6RNBUUBR.js} +2 -2
- package/dist/{chunk-DO2YPMQ5.js → chunk-C567H5EQ.js} +23 -5
- package/dist/chunk-C567H5EQ.js.map +1 -0
- package/dist/{chunk-UGJ3X4CT.js → chunk-DST4UBXU.js} +2 -2
- package/dist/{chunk-DXRZKKSO.js → chunk-NB7GJE4S.js} +2 -4
- package/dist/chunk-NB7GJE4S.js.map +1 -0
- package/dist/{chunk-HAU66QBQ.js → chunk-P4OYPFQ5.js} +9 -9
- package/dist/chunk-P4OYPFQ5.js.map +1 -0
- package/dist/{chunk-LU3PPAOQ.js → chunk-UJ2JC7PZ.js} +4 -4
- package/dist/chunk-UJ2JC7PZ.js.map +1 -0
- package/dist/{chunk-TQ54WLCZ.js → chunk-X5MAXP5T.js} +2 -1
- package/dist/{chunk-ZBTC5QIQ.js → chunk-Z35HKVSO.js} +137 -10
- package/dist/chunk-Z35HKVSO.js.map +1 -0
- package/dist/cli/init.cjs +1313 -1118
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +456 -72
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs +257 -85
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.d.cts +35 -4
- package/dist/cli/mcp-add.d.ts +35 -4
- package/dist/cli/mcp-add.js +61 -25
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/status.cjs.map +1 -1
- package/dist/cli/status.js +1 -1
- package/dist/cli/uninit.cjs +1 -1
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.js +4 -4
- package/dist/cli/validate.cjs +14162 -2
- package/dist/cli/validate.cjs.map +1 -1
- package/dist/cli/validate.d.cts +7 -3
- package/dist/cli/validate.d.ts +7 -3
- package/dist/cli/validate.js +25 -2
- package/dist/cli/validate.js.map +1 -1
- package/dist/edge-entry.js +2 -2
- package/dist/index.cjs +423 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -5
- package/dist/{monorepo-N5Z63XP7.js → monorepo-PFVNPQ6X.js} +3 -3
- package/dist/node-entry.cjs +423 -12
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.js +7 -7
- package/dist/node-subpath.js +3 -3
- package/dist/{source-map-uploader-BJIXRLJ6.js → source-map-uploader-DPUUCLNW.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-DO2YPMQ5.js.map +0 -1
- package/dist/chunk-DXRZKKSO.js.map +0 -1
- package/dist/chunk-HAU66QBQ.js.map +0 -1
- package/dist/chunk-IP4NMDJK.js +0 -98
- package/dist/chunk-IP4NMDJK.js.map +0 -1
- package/dist/chunk-LU3PPAOQ.js.map +0 -1
- package/dist/chunk-O63DJKIJ.js +0 -460
- package/dist/chunk-O63DJKIJ.js.map +0 -1
- package/dist/chunk-ZBTC5QIQ.js.map +0 -1
- /package/dist/{chunk-55FBXXER.js.map → chunk-2M57EO6U.js.map} +0 -0
- /package/dist/{chunk-KE7MCPO5.js.map → chunk-4EZ6JTDG.js.map} +0 -0
- /package/dist/{chunk-67RIOAXV.js.map → chunk-6RNBUUBR.js.map} +0 -0
- /package/dist/{chunk-UGJ3X4CT.js.map → chunk-DST4UBXU.js.map} +0 -0
- /package/dist/{chunk-TQ54WLCZ.js.map → chunk-X5MAXP5T.js.map} +0 -0
- /package/dist/{monorepo-N5Z63XP7.js.map → monorepo-PFVNPQ6X.js.map} +0 -0
- /package/dist/{source-map-uploader-BJIXRLJ6.js.map → source-map-uploader-DPUUCLNW.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -17006,6 +17006,7 @@ function classifyFetchTarget(url2) {
|
|
|
17006
17006
|
init_dist();
|
|
17007
17007
|
var GLASSTRACE_DIR = ".glasstrace";
|
|
17008
17008
|
var ANON_KEY_FILE = "anon_key";
|
|
17009
|
+
var CLAIMED_KEY_FILE = "claimed-key";
|
|
17009
17010
|
var fsPathCache;
|
|
17010
17011
|
async function loadFsPath() {
|
|
17011
17012
|
if (fsPathCache !== void 0) return fsPathCache;
|
|
@@ -17042,6 +17043,22 @@ async function readAnonKey(projectRoot) {
|
|
|
17042
17043
|
}
|
|
17043
17044
|
return null;
|
|
17044
17045
|
}
|
|
17046
|
+
async function readClaimedKey(projectRoot) {
|
|
17047
|
+
const root = projectRoot ?? process.cwd();
|
|
17048
|
+
const modules = await loadFsPath();
|
|
17049
|
+
if (!modules) return null;
|
|
17050
|
+
const keyPath = modules.path.join(root, GLASSTRACE_DIR, CLAIMED_KEY_FILE);
|
|
17051
|
+
try {
|
|
17052
|
+
const content = await modules.fs.readFile(keyPath, "utf-8");
|
|
17053
|
+
const trimmed = content.trim();
|
|
17054
|
+
const parsed = DevApiKeySchema.safeParse(trimmed);
|
|
17055
|
+
if (parsed.success) {
|
|
17056
|
+
return parsed.data;
|
|
17057
|
+
}
|
|
17058
|
+
} catch {
|
|
17059
|
+
}
|
|
17060
|
+
return null;
|
|
17061
|
+
}
|
|
17045
17062
|
async function getOrCreateAnonKey(projectRoot) {
|
|
17046
17063
|
const root = projectRoot ?? process.cwd();
|
|
17047
17064
|
const existingKey = await readAnonKey(root);
|
|
@@ -17378,8 +17395,259 @@ function sleep(ms, scheduler, signal) {
|
|
|
17378
17395
|
});
|
|
17379
17396
|
}
|
|
17380
17397
|
|
|
17381
|
-
// src/
|
|
17398
|
+
// src/mcp-runtime.ts
|
|
17399
|
+
var import_node_crypto = require("node:crypto");
|
|
17400
|
+
init_dist();
|
|
17401
|
+
var MCP_ENDPOINT = "https://api.glasstrace.dev/mcp";
|
|
17402
|
+
var fsPathCache2;
|
|
17403
|
+
async function loadFsPath2() {
|
|
17404
|
+
if (fsPathCache2 !== void 0) return fsPathCache2;
|
|
17405
|
+
try {
|
|
17406
|
+
const [fs3, path3] = await Promise.all([
|
|
17407
|
+
import("node:fs/promises"),
|
|
17408
|
+
import("node:path")
|
|
17409
|
+
]);
|
|
17410
|
+
fsPathCache2 = { fs: fs3, path: path3 };
|
|
17411
|
+
return fsPathCache2;
|
|
17412
|
+
} catch {
|
|
17413
|
+
fsPathCache2 = null;
|
|
17414
|
+
return null;
|
|
17415
|
+
}
|
|
17416
|
+
}
|
|
17417
|
+
function identityFingerprint(token) {
|
|
17418
|
+
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(token).digest("hex")}`;
|
|
17419
|
+
}
|
|
17420
|
+
function mcpConfigMatches(existingContent, expectedContent) {
|
|
17421
|
+
const trimmedExpected = expectedContent.trim();
|
|
17422
|
+
try {
|
|
17423
|
+
const existingParsed = JSON.parse(existingContent);
|
|
17424
|
+
const expectedParsed = JSON.parse(trimmedExpected);
|
|
17425
|
+
return JSON.stringify(canonicalize(existingParsed)) === JSON.stringify(canonicalize(expectedParsed));
|
|
17426
|
+
} catch {
|
|
17427
|
+
}
|
|
17428
|
+
return existingContent.trim() === trimmedExpected;
|
|
17429
|
+
}
|
|
17430
|
+
function canonicalize(value) {
|
|
17431
|
+
if (Array.isArray(value)) {
|
|
17432
|
+
return value.map(canonicalize);
|
|
17433
|
+
}
|
|
17434
|
+
if (value !== null && typeof value === "object") {
|
|
17435
|
+
const obj = value;
|
|
17436
|
+
const sorted = {};
|
|
17437
|
+
for (const key of Object.keys(obj).sort()) {
|
|
17438
|
+
sorted[key] = canonicalize(obj[key]);
|
|
17439
|
+
}
|
|
17440
|
+
return sorted;
|
|
17441
|
+
}
|
|
17442
|
+
return value;
|
|
17443
|
+
}
|
|
17444
|
+
function readEnvLocalApiKey(content) {
|
|
17445
|
+
let last = null;
|
|
17446
|
+
const regex = /^\s*GLASSTRACE_API_KEY\s*=\s*(.*)$/gm;
|
|
17447
|
+
let match;
|
|
17448
|
+
while ((match = regex.exec(content)) !== null) {
|
|
17449
|
+
const raw = match[1].trim();
|
|
17450
|
+
if (raw === "") continue;
|
|
17451
|
+
const unquoted = raw.replace(/^(['"])(.*)\1$/, "$2");
|
|
17452
|
+
if (unquoted === "" || unquoted === "your_key_here") continue;
|
|
17453
|
+
last = unquoted;
|
|
17454
|
+
}
|
|
17455
|
+
return last;
|
|
17456
|
+
}
|
|
17457
|
+
async function resolveEffectiveMcpCredential(projectRoot) {
|
|
17458
|
+
const root = projectRoot ?? process.cwd();
|
|
17459
|
+
const warnings = [];
|
|
17460
|
+
const envLocalKey = await readEnvLocalDevKey(root, warnings);
|
|
17461
|
+
const claimedKey = envLocalKey === null ? await readClaimedKey(root) : null;
|
|
17462
|
+
const anonKey = await readAnonKey(root);
|
|
17463
|
+
let effective = null;
|
|
17464
|
+
if (envLocalKey !== null) {
|
|
17465
|
+
effective = { source: "env-local", key: envLocalKey };
|
|
17466
|
+
} else if (claimedKey !== null) {
|
|
17467
|
+
effective = { source: "claimed-key", key: claimedKey };
|
|
17468
|
+
warnings.push("claimed-key-only");
|
|
17469
|
+
} else if (anonKey !== null) {
|
|
17470
|
+
effective = { source: "anon", key: anonKey };
|
|
17471
|
+
}
|
|
17472
|
+
return { effective, anonKey, warnings };
|
|
17473
|
+
}
|
|
17474
|
+
async function readEnvLocalDevKey(root, warnings) {
|
|
17475
|
+
const modules = await loadFsPath2();
|
|
17476
|
+
if (!modules) return null;
|
|
17477
|
+
const envPath = modules.path.join(root, ".env.local");
|
|
17478
|
+
let content;
|
|
17479
|
+
try {
|
|
17480
|
+
content = await modules.fs.readFile(envPath, "utf-8");
|
|
17481
|
+
} catch {
|
|
17482
|
+
return null;
|
|
17483
|
+
}
|
|
17484
|
+
const raw = readEnvLocalApiKey(content);
|
|
17485
|
+
if (raw === null) return null;
|
|
17486
|
+
const parsed = DevApiKeySchema.safeParse(raw);
|
|
17487
|
+
if (!parsed.success) {
|
|
17488
|
+
warnings.push("malformed-env-local");
|
|
17489
|
+
return null;
|
|
17490
|
+
}
|
|
17491
|
+
return parsed.data;
|
|
17492
|
+
}
|
|
17493
|
+
var MCP_MARKER_FILE = "mcp-connected";
|
|
17382
17494
|
var GLASSTRACE_DIR2 = ".glasstrace";
|
|
17495
|
+
async function readMcpMarker(projectRoot) {
|
|
17496
|
+
const root = projectRoot ?? process.cwd();
|
|
17497
|
+
const modules = await loadFsPath2();
|
|
17498
|
+
if (!modules) return { status: "absent" };
|
|
17499
|
+
const markerPath = modules.path.join(root, GLASSTRACE_DIR2, MCP_MARKER_FILE);
|
|
17500
|
+
let content;
|
|
17501
|
+
try {
|
|
17502
|
+
content = await modules.fs.readFile(markerPath, "utf-8");
|
|
17503
|
+
} catch {
|
|
17504
|
+
return { status: "absent" };
|
|
17505
|
+
}
|
|
17506
|
+
let parsed;
|
|
17507
|
+
try {
|
|
17508
|
+
parsed = JSON.parse(content);
|
|
17509
|
+
} catch {
|
|
17510
|
+
return { status: "corrupted" };
|
|
17511
|
+
}
|
|
17512
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
17513
|
+
return { status: "corrupted" };
|
|
17514
|
+
}
|
|
17515
|
+
const obj = parsed;
|
|
17516
|
+
const version2 = obj["version"];
|
|
17517
|
+
if (version2 === void 0) {
|
|
17518
|
+
const keyHash = obj["keyHash"];
|
|
17519
|
+
if (typeof keyHash !== "string" || keyHash === "") {
|
|
17520
|
+
return { status: "corrupted" };
|
|
17521
|
+
}
|
|
17522
|
+
return {
|
|
17523
|
+
status: "valid",
|
|
17524
|
+
credentialSource: "anon",
|
|
17525
|
+
credentialHash: keyHash
|
|
17526
|
+
};
|
|
17527
|
+
}
|
|
17528
|
+
if (version2 === 2) {
|
|
17529
|
+
const source = obj["credentialSource"];
|
|
17530
|
+
const hash2 = obj["credentialHash"];
|
|
17531
|
+
if (source !== "env-local" && source !== "claimed-key" && source !== "anon" || typeof hash2 !== "string" || hash2 === "") {
|
|
17532
|
+
return { status: "corrupted" };
|
|
17533
|
+
}
|
|
17534
|
+
return {
|
|
17535
|
+
status: "valid",
|
|
17536
|
+
credentialSource: source,
|
|
17537
|
+
credentialHash: hash2
|
|
17538
|
+
};
|
|
17539
|
+
}
|
|
17540
|
+
if (typeof version2 === "number" && version2 > 2) {
|
|
17541
|
+
return { status: "unknown-version" };
|
|
17542
|
+
}
|
|
17543
|
+
return { status: "corrupted" };
|
|
17544
|
+
}
|
|
17545
|
+
async function writeMcpMarker(projectRoot, target) {
|
|
17546
|
+
const modules = await loadFsPath2();
|
|
17547
|
+
if (!modules) return false;
|
|
17548
|
+
const dirPath = modules.path.join(projectRoot, GLASSTRACE_DIR2);
|
|
17549
|
+
const markerPath = modules.path.join(dirPath, MCP_MARKER_FILE);
|
|
17550
|
+
const state = await readMcpMarker(projectRoot);
|
|
17551
|
+
if (state.status === "valid" && state.credentialSource === target.credentialSource && state.credentialHash === target.credentialHash) {
|
|
17552
|
+
return false;
|
|
17553
|
+
}
|
|
17554
|
+
await modules.fs.mkdir(dirPath, { recursive: true, mode: 448 });
|
|
17555
|
+
const body = JSON.stringify(
|
|
17556
|
+
{
|
|
17557
|
+
version: 2,
|
|
17558
|
+
credentialSource: target.credentialSource,
|
|
17559
|
+
credentialHash: target.credentialHash,
|
|
17560
|
+
configuredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
17561
|
+
},
|
|
17562
|
+
null,
|
|
17563
|
+
2
|
|
17564
|
+
);
|
|
17565
|
+
await modules.fs.writeFile(markerPath, body, { mode: 384 });
|
|
17566
|
+
await modules.fs.chmod(markerPath, 384);
|
|
17567
|
+
return true;
|
|
17568
|
+
}
|
|
17569
|
+
var MCP_CONFIG_FILE = "mcp.json";
|
|
17570
|
+
var refreshNudgeEmitted = false;
|
|
17571
|
+
function emitRefreshNudge(persistedSource) {
|
|
17572
|
+
if (refreshNudgeEmitted) return;
|
|
17573
|
+
refreshNudgeEmitted = true;
|
|
17574
|
+
try {
|
|
17575
|
+
if (persistedSource === "claimed-key") {
|
|
17576
|
+
process.stderr.write(
|
|
17577
|
+
"[glasstrace] MCP config refreshed for the new credential. Copy .glasstrace/claimed-key into .env.local so Codex can pick it up on next restart.\n"
|
|
17578
|
+
);
|
|
17579
|
+
} else {
|
|
17580
|
+
process.stderr.write(
|
|
17581
|
+
"[glasstrace] MCP config refreshed for the new credential.\n"
|
|
17582
|
+
);
|
|
17583
|
+
}
|
|
17584
|
+
} catch {
|
|
17585
|
+
}
|
|
17586
|
+
}
|
|
17587
|
+
function genericMcpConfigContent(endpoint, bearer) {
|
|
17588
|
+
return JSON.stringify(
|
|
17589
|
+
{
|
|
17590
|
+
mcpServers: {
|
|
17591
|
+
glasstrace: {
|
|
17592
|
+
url: endpoint,
|
|
17593
|
+
headers: {
|
|
17594
|
+
Authorization: `Bearer ${bearer}`
|
|
17595
|
+
}
|
|
17596
|
+
}
|
|
17597
|
+
}
|
|
17598
|
+
},
|
|
17599
|
+
null,
|
|
17600
|
+
2
|
|
17601
|
+
);
|
|
17602
|
+
}
|
|
17603
|
+
async function refreshGenericMcpConfigAtRuntime(projectRoot, effective, anonKeyOnDisk) {
|
|
17604
|
+
if (effective === null || effective.source === "anon") {
|
|
17605
|
+
return { action: "skipped-anon-source" };
|
|
17606
|
+
}
|
|
17607
|
+
if (anonKeyOnDisk === null) {
|
|
17608
|
+
return { action: "absent" };
|
|
17609
|
+
}
|
|
17610
|
+
const modules = await loadFsPath2();
|
|
17611
|
+
if (!modules) return { action: "absent" };
|
|
17612
|
+
const dirPath = modules.path.join(projectRoot, GLASSTRACE_DIR2);
|
|
17613
|
+
const configPath = modules.path.join(dirPath, MCP_CONFIG_FILE);
|
|
17614
|
+
const tmpPath = configPath + ".tmp";
|
|
17615
|
+
let existing;
|
|
17616
|
+
try {
|
|
17617
|
+
existing = await modules.fs.readFile(configPath, "utf-8");
|
|
17618
|
+
} catch (err) {
|
|
17619
|
+
const code = err.code;
|
|
17620
|
+
if (code === "ENOENT") {
|
|
17621
|
+
return { action: "absent" };
|
|
17622
|
+
}
|
|
17623
|
+
return { action: "preserved" };
|
|
17624
|
+
}
|
|
17625
|
+
const expectedAnon = genericMcpConfigContent(MCP_ENDPOINT, anonKeyOnDisk);
|
|
17626
|
+
if (!mcpConfigMatches(existing, expectedAnon)) {
|
|
17627
|
+
return { action: "preserved" };
|
|
17628
|
+
}
|
|
17629
|
+
const replacement = genericMcpConfigContent(MCP_ENDPOINT, effective.key);
|
|
17630
|
+
try {
|
|
17631
|
+
await modules.fs.writeFile(tmpPath, replacement, { mode: 384 });
|
|
17632
|
+
await modules.fs.chmod(tmpPath, 384);
|
|
17633
|
+
await modules.fs.rename(tmpPath, configPath);
|
|
17634
|
+
await writeMcpMarker(projectRoot, {
|
|
17635
|
+
credentialSource: effective.source,
|
|
17636
|
+
credentialHash: identityFingerprint(effective.key)
|
|
17637
|
+
});
|
|
17638
|
+
} catch {
|
|
17639
|
+
try {
|
|
17640
|
+
await modules.fs.unlink(tmpPath);
|
|
17641
|
+
} catch {
|
|
17642
|
+
}
|
|
17643
|
+
return { action: "preserved" };
|
|
17644
|
+
}
|
|
17645
|
+
emitRefreshNudge(effective.source);
|
|
17646
|
+
return { action: "rewrote" };
|
|
17647
|
+
}
|
|
17648
|
+
|
|
17649
|
+
// src/init-client.ts
|
|
17650
|
+
var GLASSTRACE_DIR3 = ".glasstrace";
|
|
17383
17651
|
var CONFIG_FILE = "config";
|
|
17384
17652
|
var TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1e3;
|
|
17385
17653
|
var INIT_TIMEOUT_MS = 1e4;
|
|
@@ -17416,7 +17684,7 @@ function loadCachedConfig(projectRoot) {
|
|
|
17416
17684
|
const modules = loadFsSyncOrNull();
|
|
17417
17685
|
if (!modules) return null;
|
|
17418
17686
|
const root = projectRoot ?? process.cwd();
|
|
17419
|
-
const configPath = modules.join(root,
|
|
17687
|
+
const configPath = modules.join(root, GLASSTRACE_DIR3, CONFIG_FILE);
|
|
17420
17688
|
try {
|
|
17421
17689
|
const content = modules.readFileSync(configPath, "utf-8");
|
|
17422
17690
|
const parsed = JSON.parse(content);
|
|
@@ -17442,7 +17710,7 @@ async function saveCachedConfig(response, projectRoot) {
|
|
|
17442
17710
|
const modules = await loadFsPathAsync();
|
|
17443
17711
|
if (!modules) return;
|
|
17444
17712
|
const root = projectRoot ?? process.cwd();
|
|
17445
|
-
const dirPath = modules.path.join(root,
|
|
17713
|
+
const dirPath = modules.path.join(root, GLASSTRACE_DIR3);
|
|
17446
17714
|
const configPath = modules.path.join(dirPath, CONFIG_FILE);
|
|
17447
17715
|
const tmpPath = `${configPath}.tmp`;
|
|
17448
17716
|
try {
|
|
@@ -17568,11 +17836,11 @@ async function writeClaimedKey(newApiKey, projectRoot) {
|
|
|
17568
17836
|
);
|
|
17569
17837
|
} catch {
|
|
17570
17838
|
}
|
|
17571
|
-
return;
|
|
17839
|
+
return { persisted: "env-local" };
|
|
17572
17840
|
}
|
|
17573
17841
|
let claimedKeyWritten = false;
|
|
17574
17842
|
try {
|
|
17575
|
-
const dirPath = modules.path.join(root,
|
|
17843
|
+
const dirPath = modules.path.join(root, GLASSTRACE_DIR3);
|
|
17576
17844
|
await modules.fs.mkdir(dirPath, { recursive: true, mode: 448 });
|
|
17577
17845
|
await modules.fs.chmod(dirPath, 448);
|
|
17578
17846
|
const claimedKeyPath = modules.path.join(dirPath, "claimed-key");
|
|
@@ -17591,7 +17859,7 @@ async function writeClaimedKey(newApiKey, projectRoot) {
|
|
|
17591
17859
|
);
|
|
17592
17860
|
} catch {
|
|
17593
17861
|
}
|
|
17594
|
-
return;
|
|
17862
|
+
return { persisted: "claimed-key" };
|
|
17595
17863
|
}
|
|
17596
17864
|
}
|
|
17597
17865
|
try {
|
|
@@ -17600,6 +17868,7 @@ async function writeClaimedKey(newApiKey, projectRoot) {
|
|
|
17600
17868
|
);
|
|
17601
17869
|
} catch {
|
|
17602
17870
|
}
|
|
17871
|
+
return { persisted: "none" };
|
|
17603
17872
|
}
|
|
17604
17873
|
async function performInit(config2, anonKey, sdkVersion, healthReport) {
|
|
17605
17874
|
lastInitSucceeded = false;
|
|
@@ -17631,10 +17900,23 @@ async function performInit(config2, anonKey, sdkVersion, healthReport) {
|
|
|
17631
17900
|
lastInitSucceeded = true;
|
|
17632
17901
|
await saveCachedConfig(result);
|
|
17633
17902
|
if (result.claimResult) {
|
|
17903
|
+
let persisted = "none";
|
|
17634
17904
|
try {
|
|
17635
|
-
await writeClaimedKey(result.claimResult.newApiKey);
|
|
17905
|
+
const w = await writeClaimedKey(result.claimResult.newApiKey);
|
|
17906
|
+
persisted = w.persisted;
|
|
17636
17907
|
} catch {
|
|
17637
17908
|
}
|
|
17909
|
+
if (persisted !== "none") {
|
|
17910
|
+
try {
|
|
17911
|
+
const resolved = await resolveEffectiveMcpCredential();
|
|
17912
|
+
await refreshGenericMcpConfigAtRuntime(
|
|
17913
|
+
process.cwd(),
|
|
17914
|
+
resolved.effective,
|
|
17915
|
+
resolved.anonKey
|
|
17916
|
+
);
|
|
17917
|
+
} catch {
|
|
17918
|
+
}
|
|
17919
|
+
}
|
|
17638
17920
|
return { claimResult: result.claimResult };
|
|
17639
17921
|
}
|
|
17640
17922
|
return null;
|
|
@@ -17751,6 +18033,128 @@ init_esm();
|
|
|
17751
18033
|
init_dist();
|
|
17752
18034
|
init_console_capture();
|
|
17753
18035
|
init_error_nudge();
|
|
18036
|
+
|
|
18037
|
+
// src/error-response-body.ts
|
|
18038
|
+
var ERROR_RESPONSE_BODY_MAX_BYTES = 4096;
|
|
18039
|
+
var ERROR_RESPONSE_BODY_TRUNCATION_MARKER = "...[truncated]";
|
|
18040
|
+
var REDACTED = "[REDACTED]";
|
|
18041
|
+
var ERROR_STATUS_MIN = 400;
|
|
18042
|
+
var ERROR_STATUS_MAX = 599;
|
|
18043
|
+
function isHttpErrorStatus(status) {
|
|
18044
|
+
let numeric;
|
|
18045
|
+
if (typeof status === "number") {
|
|
18046
|
+
numeric = status;
|
|
18047
|
+
} else if (typeof status === "string" && status.length > 0) {
|
|
18048
|
+
numeric = Number(status);
|
|
18049
|
+
} else {
|
|
18050
|
+
return false;
|
|
18051
|
+
}
|
|
18052
|
+
if (!Number.isFinite(numeric)) return false;
|
|
18053
|
+
return numeric >= ERROR_STATUS_MIN && numeric <= ERROR_STATUS_MAX;
|
|
18054
|
+
}
|
|
18055
|
+
var REDACTION_PATTERNS = [
|
|
18056
|
+
// Order matters: redact specific token shapes BEFORE the generic
|
|
18057
|
+
// key=value catcher so a literal `Bearer eyJ…` collapses into a single
|
|
18058
|
+
// [REDACTED] and the JWT regex does not separately match the suffix.
|
|
18059
|
+
{
|
|
18060
|
+
name: "bearer",
|
|
18061
|
+
// Case-insensitive on the scheme: HTTP frameworks and proxies
|
|
18062
|
+
// round-trip the auth scheme with inconsistent casing
|
|
18063
|
+
// (`Bearer`, `bearer`, `BEARER`), and a real token leaks just as
|
|
18064
|
+
// badly under any of them.
|
|
18065
|
+
pattern: /\bBearer\s+[A-Za-z0-9._\-+/=]+/gi
|
|
18066
|
+
},
|
|
18067
|
+
{
|
|
18068
|
+
name: "jwt",
|
|
18069
|
+
// Three base64url segments separated by dots. Real JWTs encode at
|
|
18070
|
+
// minimum a small JSON header in the first segment, which alone is
|
|
18071
|
+
// typically ≥10 chars after base64url; a 16-char floor avoids false
|
|
18072
|
+
// positives on dotted text like a stack-trace frame
|
|
18073
|
+
// (`react.dom.server`) while still catching every real JWT we have
|
|
18074
|
+
// seen in the wild. Anchored with word boundaries on both sides so
|
|
18075
|
+
// a 3-dot semantic version like "next@15.4.1.2" does not match.
|
|
18076
|
+
pattern: /\b[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g
|
|
18077
|
+
},
|
|
18078
|
+
{
|
|
18079
|
+
name: "glasstrace-api-key",
|
|
18080
|
+
// gt_dev_* and gt_anon_* keys are >=24 chars of [A-Za-z0-9].
|
|
18081
|
+
pattern: /\bgt_(?:dev|anon)_[A-Za-z0-9]{16,}\b/g
|
|
18082
|
+
},
|
|
18083
|
+
{
|
|
18084
|
+
name: "aws-access-key",
|
|
18085
|
+
// 20-char prefix-fixed identifier.
|
|
18086
|
+
pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g
|
|
18087
|
+
},
|
|
18088
|
+
{
|
|
18089
|
+
name: "key-value-secret-quoted",
|
|
18090
|
+
// Quoted-string variant: (key) [:=] "<value>". The value runs to
|
|
18091
|
+
// the next unescaped closing quote so a multi-word secret like
|
|
18092
|
+
// `password="my secret phrase"` is fully consumed instead of
|
|
18093
|
+
// splitting at the first space and leaving the tail visible.
|
|
18094
|
+
// The leading `(?<![A-Za-z0-9_])` prevents matching inside
|
|
18095
|
+
// identifiers like `passwordless`. The trailing `"?` after the
|
|
18096
|
+
// keyword absorbs the closing quote in JSON-style `"apikey":
|
|
18097
|
+
// "value"` so the colon is still seen as the separator.
|
|
18098
|
+
pattern: /(?<![A-Za-z0-9_])(?:api[_-]?key|apikey|secret|password|token)"?\s*[:=]\s*"(?:[^"\\]|\\.)*"/gi
|
|
18099
|
+
},
|
|
18100
|
+
{
|
|
18101
|
+
name: "key-value-secret-bare",
|
|
18102
|
+
// Unquoted variant: (key) [:=] <bare-value>. The bare value
|
|
18103
|
+
// capture stops at common JSON/text delimiters so we redact only
|
|
18104
|
+
// the value, not surrounding structure. Listed AFTER the quoted
|
|
18105
|
+
// variant so a quoted value's surrounding `"` are consumed by
|
|
18106
|
+
// the first pattern and we never fall through here for a quoted
|
|
18107
|
+
// secret.
|
|
18108
|
+
pattern: /(?<![A-Za-z0-9_])(?:api[_-]?key|apikey|secret|password|token)"?\s*[:=]\s*[^\s,;}\]"]+/gi
|
|
18109
|
+
}
|
|
18110
|
+
];
|
|
18111
|
+
function sanitizeErrorResponseBody(body) {
|
|
18112
|
+
let out = body;
|
|
18113
|
+
for (const { pattern } of REDACTION_PATTERNS) {
|
|
18114
|
+
out = out.replace(pattern, REDACTED);
|
|
18115
|
+
}
|
|
18116
|
+
return out;
|
|
18117
|
+
}
|
|
18118
|
+
function truncateErrorResponseBody(body) {
|
|
18119
|
+
const encoder = new TextEncoder();
|
|
18120
|
+
const encoded = encoder.encode(body);
|
|
18121
|
+
if (encoded.byteLength <= ERROR_RESPONSE_BODY_MAX_BYTES) {
|
|
18122
|
+
return body;
|
|
18123
|
+
}
|
|
18124
|
+
let cut = ERROR_RESPONSE_BODY_MAX_BYTES;
|
|
18125
|
+
let scan = cut - 1;
|
|
18126
|
+
while (scan >= 0 && (encoded[scan] & 192) === 128) {
|
|
18127
|
+
scan -= 1;
|
|
18128
|
+
}
|
|
18129
|
+
if (scan >= 0) {
|
|
18130
|
+
const leading = encoded[scan];
|
|
18131
|
+
let expected = 1;
|
|
18132
|
+
if ((leading & 128) === 0) {
|
|
18133
|
+
expected = 1;
|
|
18134
|
+
} else if ((leading & 224) === 192) {
|
|
18135
|
+
expected = 2;
|
|
18136
|
+
} else if ((leading & 240) === 224) {
|
|
18137
|
+
expected = 3;
|
|
18138
|
+
} else if ((leading & 248) === 240) {
|
|
18139
|
+
expected = 4;
|
|
18140
|
+
}
|
|
18141
|
+
if (scan + expected > cut) {
|
|
18142
|
+
cut = scan;
|
|
18143
|
+
}
|
|
18144
|
+
}
|
|
18145
|
+
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
18146
|
+
const sliced = encoded.subarray(0, cut);
|
|
18147
|
+
const decoded = decoder.decode(sliced);
|
|
18148
|
+
return decoded + ERROR_RESPONSE_BODY_TRUNCATION_MARKER;
|
|
18149
|
+
}
|
|
18150
|
+
function prepareErrorResponseBody(body) {
|
|
18151
|
+
if (body.length === 0) return null;
|
|
18152
|
+
if (body.trim().length === 0) return null;
|
|
18153
|
+
const sanitized = sanitizeErrorResponseBody(body);
|
|
18154
|
+
return truncateErrorResponseBody(sanitized);
|
|
18155
|
+
}
|
|
18156
|
+
|
|
18157
|
+
// src/enriching-exporter.ts
|
|
17754
18158
|
var ATTR = GLASSTRACE_ATTRIBUTE_NAMES;
|
|
17755
18159
|
var API_KEY_PENDING = "pending";
|
|
17756
18160
|
var MAX_PENDING_SPANS = 1024;
|
|
@@ -17978,7 +18382,14 @@ var GlasstraceExporter = class {
|
|
|
17978
18382
|
if (this.getConfig().errorResponseBodies) {
|
|
17979
18383
|
const responseBody = attrs["glasstrace.internal.response_body"];
|
|
17980
18384
|
if (typeof responseBody === "string") {
|
|
17981
|
-
extra[ATTR.
|
|
18385
|
+
const enrichedStatus = extra[ATTR.HTTP_STATUS_CODE];
|
|
18386
|
+
const effectiveStatus = typeof enrichedStatus === "number" ? enrichedStatus : statusCode;
|
|
18387
|
+
if (isHttpErrorStatus(effectiveStatus)) {
|
|
18388
|
+
const prepared = prepareErrorResponseBody(responseBody);
|
|
18389
|
+
if (prepared !== null) {
|
|
18390
|
+
extra[ATTR.ERROR_RESPONSE_BODY] = prepared;
|
|
18391
|
+
}
|
|
18392
|
+
}
|
|
17982
18393
|
}
|
|
17983
18394
|
}
|
|
17984
18395
|
const spanAny = span;
|
|
@@ -21844,7 +22255,7 @@ function registerGlasstrace(options) {
|
|
|
21844
22255
|
setCoreState(CoreState.REGISTERING);
|
|
21845
22256
|
startRuntimeStateWriter({
|
|
21846
22257
|
projectRoot: process.cwd(),
|
|
21847
|
-
sdkVersion: "1.1.
|
|
22258
|
+
sdkVersion: "1.1.2"
|
|
21848
22259
|
});
|
|
21849
22260
|
const config2 = resolveConfig(options);
|
|
21850
22261
|
if (config2.verbose) {
|
|
@@ -22010,8 +22421,8 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
22010
22421
|
if (config2.verbose) {
|
|
22011
22422
|
console.info("[glasstrace] Background init firing.");
|
|
22012
22423
|
}
|
|
22013
|
-
const healthReport = collectHealthReport("1.1.
|
|
22014
|
-
const initResult = await performInit(config2, anonKeyForInit, "1.1.
|
|
22424
|
+
const healthReport = collectHealthReport("1.1.2");
|
|
22425
|
+
const initResult = await performInit(config2, anonKeyForInit, "1.1.2", healthReport);
|
|
22015
22426
|
if (generation !== registrationGeneration) return;
|
|
22016
22427
|
const currentState = getCoreState();
|
|
22017
22428
|
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
@@ -22034,7 +22445,7 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
22034
22445
|
}
|
|
22035
22446
|
maybeInstallConsoleCapture();
|
|
22036
22447
|
if (didLastInitSucceed()) {
|
|
22037
|
-
startHeartbeat(config2, anonKeyForInit, "1.1.
|
|
22448
|
+
startHeartbeat(config2, anonKeyForInit, "1.1.2", generation, (newApiKey, accountId) => {
|
|
22038
22449
|
setAuthState(AuthState.CLAIMING);
|
|
22039
22450
|
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
22040
22451
|
setResolvedApiKey(newApiKey);
|