@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.js
CHANGED
|
@@ -12,12 +12,12 @@ import {
|
|
|
12
12
|
registerGlasstrace,
|
|
13
13
|
waitForReady,
|
|
14
14
|
withGlasstraceConfig
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-Z35HKVSO.js";
|
|
16
16
|
import {
|
|
17
17
|
GlasstraceSpanProcessor,
|
|
18
18
|
SdkError,
|
|
19
19
|
captureCorrelationId
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-6RNBUUBR.js";
|
|
21
21
|
import "./chunk-DQ25VOKK.js";
|
|
22
22
|
import "./chunk-3TU62WD6.js";
|
|
23
23
|
import {
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
performInit,
|
|
28
28
|
saveCachedConfig,
|
|
29
29
|
sendInitRequest
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-C567H5EQ.js";
|
|
31
31
|
import {
|
|
32
32
|
isAnonymousMode,
|
|
33
33
|
isProductionDisabled,
|
|
@@ -37,10 +37,10 @@ import {
|
|
|
37
37
|
import {
|
|
38
38
|
getOrCreateAnonKey,
|
|
39
39
|
readAnonKey
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-3LILTM3T.js";
|
|
41
41
|
import {
|
|
42
42
|
deriveSessionId
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-X5MAXP5T.js";
|
|
44
44
|
import "./chunk-NSBPE2FW.js";
|
|
45
45
|
export {
|
|
46
46
|
GlasstraceExporter,
|
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
isMonorepoRoot,
|
|
4
4
|
parsePnpmWorkspaceYaml,
|
|
5
5
|
resolveProjectRoot
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-2M57EO6U.js";
|
|
7
|
+
import "./chunk-NB7GJE4S.js";
|
|
8
8
|
import "./chunk-NSBPE2FW.js";
|
|
9
9
|
export {
|
|
10
10
|
findNextJsApps,
|
|
@@ -12,4 +12,4 @@ export {
|
|
|
12
12
|
parsePnpmWorkspaceYaml,
|
|
13
13
|
resolveProjectRoot
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=monorepo-
|
|
15
|
+
//# sourceMappingURL=monorepo-PFVNPQ6X.js.map
|
package/dist/node-entry.cjs
CHANGED
|
@@ -17103,6 +17103,7 @@ function firstToken(value) {
|
|
|
17103
17103
|
init_dist();
|
|
17104
17104
|
var GLASSTRACE_DIR = ".glasstrace";
|
|
17105
17105
|
var ANON_KEY_FILE = "anon_key";
|
|
17106
|
+
var CLAIMED_KEY_FILE = "claimed-key";
|
|
17106
17107
|
var fsPathCache;
|
|
17107
17108
|
async function loadFsPath() {
|
|
17108
17109
|
if (fsPathCache !== void 0) return fsPathCache;
|
|
@@ -17139,6 +17140,22 @@ async function readAnonKey(projectRoot) {
|
|
|
17139
17140
|
}
|
|
17140
17141
|
return null;
|
|
17141
17142
|
}
|
|
17143
|
+
async function readClaimedKey(projectRoot) {
|
|
17144
|
+
const root = projectRoot ?? process.cwd();
|
|
17145
|
+
const modules = await loadFsPath();
|
|
17146
|
+
if (!modules) return null;
|
|
17147
|
+
const keyPath = modules.path.join(root, GLASSTRACE_DIR, CLAIMED_KEY_FILE);
|
|
17148
|
+
try {
|
|
17149
|
+
const content = await modules.fs.readFile(keyPath, "utf-8");
|
|
17150
|
+
const trimmed = content.trim();
|
|
17151
|
+
const parsed = DevApiKeySchema.safeParse(trimmed);
|
|
17152
|
+
if (parsed.success) {
|
|
17153
|
+
return parsed.data;
|
|
17154
|
+
}
|
|
17155
|
+
} catch {
|
|
17156
|
+
}
|
|
17157
|
+
return null;
|
|
17158
|
+
}
|
|
17142
17159
|
async function getOrCreateAnonKey(projectRoot) {
|
|
17143
17160
|
const root = projectRoot ?? process.cwd();
|
|
17144
17161
|
const existingKey = await readAnonKey(root);
|
|
@@ -17475,8 +17492,259 @@ function sleep(ms, scheduler, signal) {
|
|
|
17475
17492
|
});
|
|
17476
17493
|
}
|
|
17477
17494
|
|
|
17478
|
-
// src/
|
|
17495
|
+
// src/mcp-runtime.ts
|
|
17496
|
+
var import_node_crypto = require("node:crypto");
|
|
17497
|
+
init_dist();
|
|
17498
|
+
var MCP_ENDPOINT = "https://api.glasstrace.dev/mcp";
|
|
17499
|
+
var fsPathCache2;
|
|
17500
|
+
async function loadFsPath2() {
|
|
17501
|
+
if (fsPathCache2 !== void 0) return fsPathCache2;
|
|
17502
|
+
try {
|
|
17503
|
+
const [fs4, path4] = await Promise.all([
|
|
17504
|
+
import("node:fs/promises"),
|
|
17505
|
+
import("node:path")
|
|
17506
|
+
]);
|
|
17507
|
+
fsPathCache2 = { fs: fs4, path: path4 };
|
|
17508
|
+
return fsPathCache2;
|
|
17509
|
+
} catch {
|
|
17510
|
+
fsPathCache2 = null;
|
|
17511
|
+
return null;
|
|
17512
|
+
}
|
|
17513
|
+
}
|
|
17514
|
+
function identityFingerprint(token) {
|
|
17515
|
+
return `sha256:${(0, import_node_crypto.createHash)("sha256").update(token).digest("hex")}`;
|
|
17516
|
+
}
|
|
17517
|
+
function mcpConfigMatches(existingContent, expectedContent) {
|
|
17518
|
+
const trimmedExpected = expectedContent.trim();
|
|
17519
|
+
try {
|
|
17520
|
+
const existingParsed = JSON.parse(existingContent);
|
|
17521
|
+
const expectedParsed = JSON.parse(trimmedExpected);
|
|
17522
|
+
return JSON.stringify(canonicalize(existingParsed)) === JSON.stringify(canonicalize(expectedParsed));
|
|
17523
|
+
} catch {
|
|
17524
|
+
}
|
|
17525
|
+
return existingContent.trim() === trimmedExpected;
|
|
17526
|
+
}
|
|
17527
|
+
function canonicalize(value) {
|
|
17528
|
+
if (Array.isArray(value)) {
|
|
17529
|
+
return value.map(canonicalize);
|
|
17530
|
+
}
|
|
17531
|
+
if (value !== null && typeof value === "object") {
|
|
17532
|
+
const obj = value;
|
|
17533
|
+
const sorted = {};
|
|
17534
|
+
for (const key of Object.keys(obj).sort()) {
|
|
17535
|
+
sorted[key] = canonicalize(obj[key]);
|
|
17536
|
+
}
|
|
17537
|
+
return sorted;
|
|
17538
|
+
}
|
|
17539
|
+
return value;
|
|
17540
|
+
}
|
|
17541
|
+
function readEnvLocalApiKey(content) {
|
|
17542
|
+
let last = null;
|
|
17543
|
+
const regex = /^\s*GLASSTRACE_API_KEY\s*=\s*(.*)$/gm;
|
|
17544
|
+
let match;
|
|
17545
|
+
while ((match = regex.exec(content)) !== null) {
|
|
17546
|
+
const raw = match[1].trim();
|
|
17547
|
+
if (raw === "") continue;
|
|
17548
|
+
const unquoted = raw.replace(/^(['"])(.*)\1$/, "$2");
|
|
17549
|
+
if (unquoted === "" || unquoted === "your_key_here") continue;
|
|
17550
|
+
last = unquoted;
|
|
17551
|
+
}
|
|
17552
|
+
return last;
|
|
17553
|
+
}
|
|
17554
|
+
async function resolveEffectiveMcpCredential(projectRoot) {
|
|
17555
|
+
const root = projectRoot ?? process.cwd();
|
|
17556
|
+
const warnings = [];
|
|
17557
|
+
const envLocalKey = await readEnvLocalDevKey(root, warnings);
|
|
17558
|
+
const claimedKey = envLocalKey === null ? await readClaimedKey(root) : null;
|
|
17559
|
+
const anonKey = await readAnonKey(root);
|
|
17560
|
+
let effective = null;
|
|
17561
|
+
if (envLocalKey !== null) {
|
|
17562
|
+
effective = { source: "env-local", key: envLocalKey };
|
|
17563
|
+
} else if (claimedKey !== null) {
|
|
17564
|
+
effective = { source: "claimed-key", key: claimedKey };
|
|
17565
|
+
warnings.push("claimed-key-only");
|
|
17566
|
+
} else if (anonKey !== null) {
|
|
17567
|
+
effective = { source: "anon", key: anonKey };
|
|
17568
|
+
}
|
|
17569
|
+
return { effective, anonKey, warnings };
|
|
17570
|
+
}
|
|
17571
|
+
async function readEnvLocalDevKey(root, warnings) {
|
|
17572
|
+
const modules = await loadFsPath2();
|
|
17573
|
+
if (!modules) return null;
|
|
17574
|
+
const envPath = modules.path.join(root, ".env.local");
|
|
17575
|
+
let content;
|
|
17576
|
+
try {
|
|
17577
|
+
content = await modules.fs.readFile(envPath, "utf-8");
|
|
17578
|
+
} catch {
|
|
17579
|
+
return null;
|
|
17580
|
+
}
|
|
17581
|
+
const raw = readEnvLocalApiKey(content);
|
|
17582
|
+
if (raw === null) return null;
|
|
17583
|
+
const parsed = DevApiKeySchema.safeParse(raw);
|
|
17584
|
+
if (!parsed.success) {
|
|
17585
|
+
warnings.push("malformed-env-local");
|
|
17586
|
+
return null;
|
|
17587
|
+
}
|
|
17588
|
+
return parsed.data;
|
|
17589
|
+
}
|
|
17590
|
+
var MCP_MARKER_FILE = "mcp-connected";
|
|
17479
17591
|
var GLASSTRACE_DIR2 = ".glasstrace";
|
|
17592
|
+
async function readMcpMarker(projectRoot) {
|
|
17593
|
+
const root = projectRoot ?? process.cwd();
|
|
17594
|
+
const modules = await loadFsPath2();
|
|
17595
|
+
if (!modules) return { status: "absent" };
|
|
17596
|
+
const markerPath = modules.path.join(root, GLASSTRACE_DIR2, MCP_MARKER_FILE);
|
|
17597
|
+
let content;
|
|
17598
|
+
try {
|
|
17599
|
+
content = await modules.fs.readFile(markerPath, "utf-8");
|
|
17600
|
+
} catch {
|
|
17601
|
+
return { status: "absent" };
|
|
17602
|
+
}
|
|
17603
|
+
let parsed;
|
|
17604
|
+
try {
|
|
17605
|
+
parsed = JSON.parse(content);
|
|
17606
|
+
} catch {
|
|
17607
|
+
return { status: "corrupted" };
|
|
17608
|
+
}
|
|
17609
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
17610
|
+
return { status: "corrupted" };
|
|
17611
|
+
}
|
|
17612
|
+
const obj = parsed;
|
|
17613
|
+
const version2 = obj["version"];
|
|
17614
|
+
if (version2 === void 0) {
|
|
17615
|
+
const keyHash = obj["keyHash"];
|
|
17616
|
+
if (typeof keyHash !== "string" || keyHash === "") {
|
|
17617
|
+
return { status: "corrupted" };
|
|
17618
|
+
}
|
|
17619
|
+
return {
|
|
17620
|
+
status: "valid",
|
|
17621
|
+
credentialSource: "anon",
|
|
17622
|
+
credentialHash: keyHash
|
|
17623
|
+
};
|
|
17624
|
+
}
|
|
17625
|
+
if (version2 === 2) {
|
|
17626
|
+
const source = obj["credentialSource"];
|
|
17627
|
+
const hash2 = obj["credentialHash"];
|
|
17628
|
+
if (source !== "env-local" && source !== "claimed-key" && source !== "anon" || typeof hash2 !== "string" || hash2 === "") {
|
|
17629
|
+
return { status: "corrupted" };
|
|
17630
|
+
}
|
|
17631
|
+
return {
|
|
17632
|
+
status: "valid",
|
|
17633
|
+
credentialSource: source,
|
|
17634
|
+
credentialHash: hash2
|
|
17635
|
+
};
|
|
17636
|
+
}
|
|
17637
|
+
if (typeof version2 === "number" && version2 > 2) {
|
|
17638
|
+
return { status: "unknown-version" };
|
|
17639
|
+
}
|
|
17640
|
+
return { status: "corrupted" };
|
|
17641
|
+
}
|
|
17642
|
+
async function writeMcpMarker(projectRoot, target) {
|
|
17643
|
+
const modules = await loadFsPath2();
|
|
17644
|
+
if (!modules) return false;
|
|
17645
|
+
const dirPath = modules.path.join(projectRoot, GLASSTRACE_DIR2);
|
|
17646
|
+
const markerPath = modules.path.join(dirPath, MCP_MARKER_FILE);
|
|
17647
|
+
const state = await readMcpMarker(projectRoot);
|
|
17648
|
+
if (state.status === "valid" && state.credentialSource === target.credentialSource && state.credentialHash === target.credentialHash) {
|
|
17649
|
+
return false;
|
|
17650
|
+
}
|
|
17651
|
+
await modules.fs.mkdir(dirPath, { recursive: true, mode: 448 });
|
|
17652
|
+
const body = JSON.stringify(
|
|
17653
|
+
{
|
|
17654
|
+
version: 2,
|
|
17655
|
+
credentialSource: target.credentialSource,
|
|
17656
|
+
credentialHash: target.credentialHash,
|
|
17657
|
+
configuredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
17658
|
+
},
|
|
17659
|
+
null,
|
|
17660
|
+
2
|
|
17661
|
+
);
|
|
17662
|
+
await modules.fs.writeFile(markerPath, body, { mode: 384 });
|
|
17663
|
+
await modules.fs.chmod(markerPath, 384);
|
|
17664
|
+
return true;
|
|
17665
|
+
}
|
|
17666
|
+
var MCP_CONFIG_FILE = "mcp.json";
|
|
17667
|
+
var refreshNudgeEmitted = false;
|
|
17668
|
+
function emitRefreshNudge(persistedSource) {
|
|
17669
|
+
if (refreshNudgeEmitted) return;
|
|
17670
|
+
refreshNudgeEmitted = true;
|
|
17671
|
+
try {
|
|
17672
|
+
if (persistedSource === "claimed-key") {
|
|
17673
|
+
process.stderr.write(
|
|
17674
|
+
"[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"
|
|
17675
|
+
);
|
|
17676
|
+
} else {
|
|
17677
|
+
process.stderr.write(
|
|
17678
|
+
"[glasstrace] MCP config refreshed for the new credential.\n"
|
|
17679
|
+
);
|
|
17680
|
+
}
|
|
17681
|
+
} catch {
|
|
17682
|
+
}
|
|
17683
|
+
}
|
|
17684
|
+
function genericMcpConfigContent(endpoint, bearer) {
|
|
17685
|
+
return JSON.stringify(
|
|
17686
|
+
{
|
|
17687
|
+
mcpServers: {
|
|
17688
|
+
glasstrace: {
|
|
17689
|
+
url: endpoint,
|
|
17690
|
+
headers: {
|
|
17691
|
+
Authorization: `Bearer ${bearer}`
|
|
17692
|
+
}
|
|
17693
|
+
}
|
|
17694
|
+
}
|
|
17695
|
+
},
|
|
17696
|
+
null,
|
|
17697
|
+
2
|
|
17698
|
+
);
|
|
17699
|
+
}
|
|
17700
|
+
async function refreshGenericMcpConfigAtRuntime(projectRoot, effective, anonKeyOnDisk) {
|
|
17701
|
+
if (effective === null || effective.source === "anon") {
|
|
17702
|
+
return { action: "skipped-anon-source" };
|
|
17703
|
+
}
|
|
17704
|
+
if (anonKeyOnDisk === null) {
|
|
17705
|
+
return { action: "absent" };
|
|
17706
|
+
}
|
|
17707
|
+
const modules = await loadFsPath2();
|
|
17708
|
+
if (!modules) return { action: "absent" };
|
|
17709
|
+
const dirPath = modules.path.join(projectRoot, GLASSTRACE_DIR2);
|
|
17710
|
+
const configPath = modules.path.join(dirPath, MCP_CONFIG_FILE);
|
|
17711
|
+
const tmpPath = configPath + ".tmp";
|
|
17712
|
+
let existing;
|
|
17713
|
+
try {
|
|
17714
|
+
existing = await modules.fs.readFile(configPath, "utf-8");
|
|
17715
|
+
} catch (err) {
|
|
17716
|
+
const code = err.code;
|
|
17717
|
+
if (code === "ENOENT") {
|
|
17718
|
+
return { action: "absent" };
|
|
17719
|
+
}
|
|
17720
|
+
return { action: "preserved" };
|
|
17721
|
+
}
|
|
17722
|
+
const expectedAnon = genericMcpConfigContent(MCP_ENDPOINT, anonKeyOnDisk);
|
|
17723
|
+
if (!mcpConfigMatches(existing, expectedAnon)) {
|
|
17724
|
+
return { action: "preserved" };
|
|
17725
|
+
}
|
|
17726
|
+
const replacement = genericMcpConfigContent(MCP_ENDPOINT, effective.key);
|
|
17727
|
+
try {
|
|
17728
|
+
await modules.fs.writeFile(tmpPath, replacement, { mode: 384 });
|
|
17729
|
+
await modules.fs.chmod(tmpPath, 384);
|
|
17730
|
+
await modules.fs.rename(tmpPath, configPath);
|
|
17731
|
+
await writeMcpMarker(projectRoot, {
|
|
17732
|
+
credentialSource: effective.source,
|
|
17733
|
+
credentialHash: identityFingerprint(effective.key)
|
|
17734
|
+
});
|
|
17735
|
+
} catch {
|
|
17736
|
+
try {
|
|
17737
|
+
await modules.fs.unlink(tmpPath);
|
|
17738
|
+
} catch {
|
|
17739
|
+
}
|
|
17740
|
+
return { action: "preserved" };
|
|
17741
|
+
}
|
|
17742
|
+
emitRefreshNudge(effective.source);
|
|
17743
|
+
return { action: "rewrote" };
|
|
17744
|
+
}
|
|
17745
|
+
|
|
17746
|
+
// src/init-client.ts
|
|
17747
|
+
var GLASSTRACE_DIR3 = ".glasstrace";
|
|
17480
17748
|
var CONFIG_FILE = "config";
|
|
17481
17749
|
var TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1e3;
|
|
17482
17750
|
var INIT_TIMEOUT_MS = 1e4;
|
|
@@ -17513,7 +17781,7 @@ function loadCachedConfig(projectRoot) {
|
|
|
17513
17781
|
const modules = loadFsSyncOrNull();
|
|
17514
17782
|
if (!modules) return null;
|
|
17515
17783
|
const root = projectRoot ?? process.cwd();
|
|
17516
|
-
const configPath = modules.join(root,
|
|
17784
|
+
const configPath = modules.join(root, GLASSTRACE_DIR3, CONFIG_FILE);
|
|
17517
17785
|
try {
|
|
17518
17786
|
const content = modules.readFileSync(configPath, "utf-8");
|
|
17519
17787
|
const parsed = JSON.parse(content);
|
|
@@ -17539,7 +17807,7 @@ async function saveCachedConfig(response, projectRoot) {
|
|
|
17539
17807
|
const modules = await loadFsPathAsync();
|
|
17540
17808
|
if (!modules) return;
|
|
17541
17809
|
const root = projectRoot ?? process.cwd();
|
|
17542
|
-
const dirPath = modules.path.join(root,
|
|
17810
|
+
const dirPath = modules.path.join(root, GLASSTRACE_DIR3);
|
|
17543
17811
|
const configPath = modules.path.join(dirPath, CONFIG_FILE);
|
|
17544
17812
|
const tmpPath = `${configPath}.tmp`;
|
|
17545
17813
|
try {
|
|
@@ -17665,11 +17933,11 @@ async function writeClaimedKey(newApiKey, projectRoot) {
|
|
|
17665
17933
|
);
|
|
17666
17934
|
} catch {
|
|
17667
17935
|
}
|
|
17668
|
-
return;
|
|
17936
|
+
return { persisted: "env-local" };
|
|
17669
17937
|
}
|
|
17670
17938
|
let claimedKeyWritten = false;
|
|
17671
17939
|
try {
|
|
17672
|
-
const dirPath = modules.path.join(root,
|
|
17940
|
+
const dirPath = modules.path.join(root, GLASSTRACE_DIR3);
|
|
17673
17941
|
await modules.fs.mkdir(dirPath, { recursive: true, mode: 448 });
|
|
17674
17942
|
await modules.fs.chmod(dirPath, 448);
|
|
17675
17943
|
const claimedKeyPath = modules.path.join(dirPath, "claimed-key");
|
|
@@ -17688,7 +17956,7 @@ async function writeClaimedKey(newApiKey, projectRoot) {
|
|
|
17688
17956
|
);
|
|
17689
17957
|
} catch {
|
|
17690
17958
|
}
|
|
17691
|
-
return;
|
|
17959
|
+
return { persisted: "claimed-key" };
|
|
17692
17960
|
}
|
|
17693
17961
|
}
|
|
17694
17962
|
try {
|
|
@@ -17697,6 +17965,7 @@ async function writeClaimedKey(newApiKey, projectRoot) {
|
|
|
17697
17965
|
);
|
|
17698
17966
|
} catch {
|
|
17699
17967
|
}
|
|
17968
|
+
return { persisted: "none" };
|
|
17700
17969
|
}
|
|
17701
17970
|
async function performInit(config2, anonKey, sdkVersion, healthReport) {
|
|
17702
17971
|
lastInitSucceeded = false;
|
|
@@ -17728,10 +17997,23 @@ async function performInit(config2, anonKey, sdkVersion, healthReport) {
|
|
|
17728
17997
|
lastInitSucceeded = true;
|
|
17729
17998
|
await saveCachedConfig(result);
|
|
17730
17999
|
if (result.claimResult) {
|
|
18000
|
+
let persisted = "none";
|
|
17731
18001
|
try {
|
|
17732
|
-
await writeClaimedKey(result.claimResult.newApiKey);
|
|
18002
|
+
const w = await writeClaimedKey(result.claimResult.newApiKey);
|
|
18003
|
+
persisted = w.persisted;
|
|
17733
18004
|
} catch {
|
|
17734
18005
|
}
|
|
18006
|
+
if (persisted !== "none") {
|
|
18007
|
+
try {
|
|
18008
|
+
const resolved = await resolveEffectiveMcpCredential();
|
|
18009
|
+
await refreshGenericMcpConfigAtRuntime(
|
|
18010
|
+
process.cwd(),
|
|
18011
|
+
resolved.effective,
|
|
18012
|
+
resolved.anonKey
|
|
18013
|
+
);
|
|
18014
|
+
} catch {
|
|
18015
|
+
}
|
|
18016
|
+
}
|
|
17735
18017
|
return { claimResult: result.claimResult };
|
|
17736
18018
|
}
|
|
17737
18019
|
return null;
|
|
@@ -17827,6 +18109,128 @@ init_esm();
|
|
|
17827
18109
|
init_dist();
|
|
17828
18110
|
init_console_capture();
|
|
17829
18111
|
init_error_nudge();
|
|
18112
|
+
|
|
18113
|
+
// src/error-response-body.ts
|
|
18114
|
+
var ERROR_RESPONSE_BODY_MAX_BYTES = 4096;
|
|
18115
|
+
var ERROR_RESPONSE_BODY_TRUNCATION_MARKER = "...[truncated]";
|
|
18116
|
+
var REDACTED = "[REDACTED]";
|
|
18117
|
+
var ERROR_STATUS_MIN = 400;
|
|
18118
|
+
var ERROR_STATUS_MAX = 599;
|
|
18119
|
+
function isHttpErrorStatus(status) {
|
|
18120
|
+
let numeric;
|
|
18121
|
+
if (typeof status === "number") {
|
|
18122
|
+
numeric = status;
|
|
18123
|
+
} else if (typeof status === "string" && status.length > 0) {
|
|
18124
|
+
numeric = Number(status);
|
|
18125
|
+
} else {
|
|
18126
|
+
return false;
|
|
18127
|
+
}
|
|
18128
|
+
if (!Number.isFinite(numeric)) return false;
|
|
18129
|
+
return numeric >= ERROR_STATUS_MIN && numeric <= ERROR_STATUS_MAX;
|
|
18130
|
+
}
|
|
18131
|
+
var REDACTION_PATTERNS = [
|
|
18132
|
+
// Order matters: redact specific token shapes BEFORE the generic
|
|
18133
|
+
// key=value catcher so a literal `Bearer eyJ…` collapses into a single
|
|
18134
|
+
// [REDACTED] and the JWT regex does not separately match the suffix.
|
|
18135
|
+
{
|
|
18136
|
+
name: "bearer",
|
|
18137
|
+
// Case-insensitive on the scheme: HTTP frameworks and proxies
|
|
18138
|
+
// round-trip the auth scheme with inconsistent casing
|
|
18139
|
+
// (`Bearer`, `bearer`, `BEARER`), and a real token leaks just as
|
|
18140
|
+
// badly under any of them.
|
|
18141
|
+
pattern: /\bBearer\s+[A-Za-z0-9._\-+/=]+/gi
|
|
18142
|
+
},
|
|
18143
|
+
{
|
|
18144
|
+
name: "jwt",
|
|
18145
|
+
// Three base64url segments separated by dots. Real JWTs encode at
|
|
18146
|
+
// minimum a small JSON header in the first segment, which alone is
|
|
18147
|
+
// typically ≥10 chars after base64url; a 16-char floor avoids false
|
|
18148
|
+
// positives on dotted text like a stack-trace frame
|
|
18149
|
+
// (`react.dom.server`) while still catching every real JWT we have
|
|
18150
|
+
// seen in the wild. Anchored with word boundaries on both sides so
|
|
18151
|
+
// a 3-dot semantic version like "next@15.4.1.2" does not match.
|
|
18152
|
+
pattern: /\b[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g
|
|
18153
|
+
},
|
|
18154
|
+
{
|
|
18155
|
+
name: "glasstrace-api-key",
|
|
18156
|
+
// gt_dev_* and gt_anon_* keys are >=24 chars of [A-Za-z0-9].
|
|
18157
|
+
pattern: /\bgt_(?:dev|anon)_[A-Za-z0-9]{16,}\b/g
|
|
18158
|
+
},
|
|
18159
|
+
{
|
|
18160
|
+
name: "aws-access-key",
|
|
18161
|
+
// 20-char prefix-fixed identifier.
|
|
18162
|
+
pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g
|
|
18163
|
+
},
|
|
18164
|
+
{
|
|
18165
|
+
name: "key-value-secret-quoted",
|
|
18166
|
+
// Quoted-string variant: (key) [:=] "<value>". The value runs to
|
|
18167
|
+
// the next unescaped closing quote so a multi-word secret like
|
|
18168
|
+
// `password="my secret phrase"` is fully consumed instead of
|
|
18169
|
+
// splitting at the first space and leaving the tail visible.
|
|
18170
|
+
// The leading `(?<![A-Za-z0-9_])` prevents matching inside
|
|
18171
|
+
// identifiers like `passwordless`. The trailing `"?` after the
|
|
18172
|
+
// keyword absorbs the closing quote in JSON-style `"apikey":
|
|
18173
|
+
// "value"` so the colon is still seen as the separator.
|
|
18174
|
+
pattern: /(?<![A-Za-z0-9_])(?:api[_-]?key|apikey|secret|password|token)"?\s*[:=]\s*"(?:[^"\\]|\\.)*"/gi
|
|
18175
|
+
},
|
|
18176
|
+
{
|
|
18177
|
+
name: "key-value-secret-bare",
|
|
18178
|
+
// Unquoted variant: (key) [:=] <bare-value>. The bare value
|
|
18179
|
+
// capture stops at common JSON/text delimiters so we redact only
|
|
18180
|
+
// the value, not surrounding structure. Listed AFTER the quoted
|
|
18181
|
+
// variant so a quoted value's surrounding `"` are consumed by
|
|
18182
|
+
// the first pattern and we never fall through here for a quoted
|
|
18183
|
+
// secret.
|
|
18184
|
+
pattern: /(?<![A-Za-z0-9_])(?:api[_-]?key|apikey|secret|password|token)"?\s*[:=]\s*[^\s,;}\]"]+/gi
|
|
18185
|
+
}
|
|
18186
|
+
];
|
|
18187
|
+
function sanitizeErrorResponseBody(body) {
|
|
18188
|
+
let out = body;
|
|
18189
|
+
for (const { pattern } of REDACTION_PATTERNS) {
|
|
18190
|
+
out = out.replace(pattern, REDACTED);
|
|
18191
|
+
}
|
|
18192
|
+
return out;
|
|
18193
|
+
}
|
|
18194
|
+
function truncateErrorResponseBody(body) {
|
|
18195
|
+
const encoder = new TextEncoder();
|
|
18196
|
+
const encoded = encoder.encode(body);
|
|
18197
|
+
if (encoded.byteLength <= ERROR_RESPONSE_BODY_MAX_BYTES) {
|
|
18198
|
+
return body;
|
|
18199
|
+
}
|
|
18200
|
+
let cut = ERROR_RESPONSE_BODY_MAX_BYTES;
|
|
18201
|
+
let scan = cut - 1;
|
|
18202
|
+
while (scan >= 0 && (encoded[scan] & 192) === 128) {
|
|
18203
|
+
scan -= 1;
|
|
18204
|
+
}
|
|
18205
|
+
if (scan >= 0) {
|
|
18206
|
+
const leading = encoded[scan];
|
|
18207
|
+
let expected = 1;
|
|
18208
|
+
if ((leading & 128) === 0) {
|
|
18209
|
+
expected = 1;
|
|
18210
|
+
} else if ((leading & 224) === 192) {
|
|
18211
|
+
expected = 2;
|
|
18212
|
+
} else if ((leading & 240) === 224) {
|
|
18213
|
+
expected = 3;
|
|
18214
|
+
} else if ((leading & 248) === 240) {
|
|
18215
|
+
expected = 4;
|
|
18216
|
+
}
|
|
18217
|
+
if (scan + expected > cut) {
|
|
18218
|
+
cut = scan;
|
|
18219
|
+
}
|
|
18220
|
+
}
|
|
18221
|
+
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
18222
|
+
const sliced = encoded.subarray(0, cut);
|
|
18223
|
+
const decoded = decoder.decode(sliced);
|
|
18224
|
+
return decoded + ERROR_RESPONSE_BODY_TRUNCATION_MARKER;
|
|
18225
|
+
}
|
|
18226
|
+
function prepareErrorResponseBody(body) {
|
|
18227
|
+
if (body.length === 0) return null;
|
|
18228
|
+
if (body.trim().length === 0) return null;
|
|
18229
|
+
const sanitized = sanitizeErrorResponseBody(body);
|
|
18230
|
+
return truncateErrorResponseBody(sanitized);
|
|
18231
|
+
}
|
|
18232
|
+
|
|
18233
|
+
// src/enriching-exporter.ts
|
|
17830
18234
|
var ATTR2 = GLASSTRACE_ATTRIBUTE_NAMES;
|
|
17831
18235
|
var API_KEY_PENDING = "pending";
|
|
17832
18236
|
var MAX_PENDING_SPANS = 1024;
|
|
@@ -18054,7 +18458,14 @@ var GlasstraceExporter = class {
|
|
|
18054
18458
|
if (this.getConfig().errorResponseBodies) {
|
|
18055
18459
|
const responseBody = attrs["glasstrace.internal.response_body"];
|
|
18056
18460
|
if (typeof responseBody === "string") {
|
|
18057
|
-
extra[ATTR2.
|
|
18461
|
+
const enrichedStatus = extra[ATTR2.HTTP_STATUS_CODE];
|
|
18462
|
+
const effectiveStatus = typeof enrichedStatus === "number" ? enrichedStatus : statusCode;
|
|
18463
|
+
if (isHttpErrorStatus(effectiveStatus)) {
|
|
18464
|
+
const prepared = prepareErrorResponseBody(responseBody);
|
|
18465
|
+
if (prepared !== null) {
|
|
18466
|
+
extra[ATTR2.ERROR_RESPONSE_BODY] = prepared;
|
|
18467
|
+
}
|
|
18468
|
+
}
|
|
18058
18469
|
}
|
|
18059
18470
|
}
|
|
18060
18471
|
const spanAny = span;
|
|
@@ -21920,7 +22331,7 @@ function registerGlasstrace(options) {
|
|
|
21920
22331
|
setCoreState(CoreState.REGISTERING);
|
|
21921
22332
|
startRuntimeStateWriter({
|
|
21922
22333
|
projectRoot: process.cwd(),
|
|
21923
|
-
sdkVersion: "1.1.
|
|
22334
|
+
sdkVersion: "1.1.2"
|
|
21924
22335
|
});
|
|
21925
22336
|
const config2 = resolveConfig(options);
|
|
21926
22337
|
if (config2.verbose) {
|
|
@@ -22086,8 +22497,8 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
22086
22497
|
if (config2.verbose) {
|
|
22087
22498
|
console.info("[glasstrace] Background init firing.");
|
|
22088
22499
|
}
|
|
22089
|
-
const healthReport = collectHealthReport("1.1.
|
|
22090
|
-
const initResult = await performInit(config2, anonKeyForInit, "1.1.
|
|
22500
|
+
const healthReport = collectHealthReport("1.1.2");
|
|
22501
|
+
const initResult = await performInit(config2, anonKeyForInit, "1.1.2", healthReport);
|
|
22091
22502
|
if (generation !== registrationGeneration) return;
|
|
22092
22503
|
const currentState = getCoreState();
|
|
22093
22504
|
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
@@ -22110,7 +22521,7 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
22110
22521
|
}
|
|
22111
22522
|
maybeInstallConsoleCapture();
|
|
22112
22523
|
if (didLastInitSucceed()) {
|
|
22113
|
-
startHeartbeat(config2, anonKeyForInit, "1.1.
|
|
22524
|
+
startHeartbeat(config2, anonKeyForInit, "1.1.2", generation, (newApiKey, accountId) => {
|
|
22114
22525
|
setAuthState(AuthState.CLAIMING);
|
|
22115
22526
|
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
22116
22527
|
setResolvedApiKey(newApiKey);
|