@glasstrace/sdk 1.1.1 → 1.1.3
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-DIM4JRXM.js → chunk-2M57EO6U.js} +2 -2
- package/dist/{chunk-Y26HJUPD.js → chunk-FGDS33I2.js} +138 -12
- package/dist/chunk-FGDS33I2.js.map +1 -0
- package/dist/{chunk-MXDZHFJQ.js → chunk-JKI4OCFV.js} +4 -14
- package/dist/chunk-JKI4OCFV.js.map +1 -0
- package/dist/{chunk-7SZQN6IU.js → chunk-NB7GJE4S.js} +2 -2
- package/dist/chunk-NB7GJE4S.js.map +1 -0
- package/dist/{chunk-ZRDQ6ZKI.js → chunk-TWHCJKRS.js} +101 -481
- package/dist/chunk-TWHCJKRS.js.map +1 -0
- package/dist/{chunk-P22UQ2OJ.js → chunk-TWTWRJ25.js} +233 -9
- package/dist/chunk-TWTWRJ25.js.map +1 -0
- package/dist/cli/init.cjs +2494 -2332
- package/dist/cli/init.cjs.map +1 -1
- package/dist/cli/init.js +434 -63
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/mcp-add.cjs +14 -2
- package/dist/cli/mcp-add.cjs.map +1 -1
- package/dist/cli/mcp-add.js +17 -5
- package/dist/cli/mcp-add.js.map +1 -1
- package/dist/cli/status.cjs.map +1 -1
- package/dist/cli/status.js +1 -3
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/uninit.cjs +116 -14
- package/dist/cli/uninit.cjs.map +1 -1
- package/dist/cli/uninit.js +3 -3
- 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/index.cjs +339 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -9
- package/dist/index.d.ts +12 -9
- package/dist/index.js +3 -3
- package/dist/{monorepo-GSL6JD3G.js → monorepo-PFVNPQ6X.js} +3 -5
- package/dist/node-entry.cjs +339 -28
- package/dist/node-entry.cjs.map +1 -1
- package/dist/node-entry.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-7SZQN6IU.js.map +0 -1
- package/dist/chunk-MXDZHFJQ.js.map +0 -1
- package/dist/chunk-P22UQ2OJ.js.map +0 -1
- package/dist/chunk-Y26HJUPD.js.map +0 -1
- package/dist/chunk-ZRDQ6ZKI.js.map +0 -1
- /package/dist/{chunk-DIM4JRXM.js.map → chunk-2M57EO6U.js.map} +0 -0
- /package/dist/{monorepo-GSL6JD3G.js.map → monorepo-PFVNPQ6X.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -88,15 +88,18 @@ declare function getOrCreateAnonKey(projectRoot?: string): Promise<AnonApiKey>;
|
|
|
88
88
|
*/
|
|
89
89
|
declare function loadCachedConfig(projectRoot?: string): SdkInitResponse | null;
|
|
90
90
|
/**
|
|
91
|
-
* Persists the init response to `.glasstrace/config` using
|
|
92
|
-
* write
|
|
93
|
-
* unavailable (non-Node environments).
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
91
|
+
* Persists the init response to `.glasstrace/config` using the SDK 2.0
|
|
92
|
+
* atomic-write protocol (`tmp + fsync(tmp) + rename + fsync(parent)`).
|
|
93
|
+
* Silently skipped when `node:fs` is unavailable (non-Node environments).
|
|
94
|
+
* On I/O failure, logs a warning.
|
|
95
|
+
*
|
|
96
|
+
* Atomicity: the payload is written to `.glasstrace/config.tmp`, fsynced
|
|
97
|
+
* to durable storage, then renamed into place; the parent directory is
|
|
98
|
+
* fsynced last so the rename survives an immediate crash. `rename` is
|
|
99
|
+
* atomic on POSIX filesystems, so readers either see the previous valid
|
|
100
|
+
* config or the new valid config — never a truncated or partially-written
|
|
101
|
+
* file (DISC-1247 Scenario 5). If any step fails, the temp file is
|
|
102
|
+
* cleaned up on a best-effort basis.
|
|
100
103
|
*/
|
|
101
104
|
declare function saveCachedConfig(response: SdkInitResponse, projectRoot?: string): Promise<void>;
|
|
102
105
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -88,15 +88,18 @@ declare function getOrCreateAnonKey(projectRoot?: string): Promise<AnonApiKey>;
|
|
|
88
88
|
*/
|
|
89
89
|
declare function loadCachedConfig(projectRoot?: string): SdkInitResponse | null;
|
|
90
90
|
/**
|
|
91
|
-
* Persists the init response to `.glasstrace/config` using
|
|
92
|
-
* write
|
|
93
|
-
* unavailable (non-Node environments).
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
91
|
+
* Persists the init response to `.glasstrace/config` using the SDK 2.0
|
|
92
|
+
* atomic-write protocol (`tmp + fsync(tmp) + rename + fsync(parent)`).
|
|
93
|
+
* Silently skipped when `node:fs` is unavailable (non-Node environments).
|
|
94
|
+
* On I/O failure, logs a warning.
|
|
95
|
+
*
|
|
96
|
+
* Atomicity: the payload is written to `.glasstrace/config.tmp`, fsynced
|
|
97
|
+
* to durable storage, then renamed into place; the parent directory is
|
|
98
|
+
* fsynced last so the rename survives an immediate crash. `rename` is
|
|
99
|
+
* atomic on POSIX filesystems, so readers either see the previous valid
|
|
100
|
+
* config or the new valid config — never a truncated or partially-written
|
|
101
|
+
* file (DISC-1247 Scenario 5). If any step fails, the temp file is
|
|
102
|
+
* cleaned up on a best-effort basis.
|
|
100
103
|
*/
|
|
101
104
|
declare function saveCachedConfig(response: SdkInitResponse, projectRoot?: string): Promise<void>;
|
|
102
105
|
/**
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
registerGlasstrace,
|
|
13
13
|
waitForReady,
|
|
14
14
|
withGlasstraceConfig
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-FGDS33I2.js";
|
|
16
16
|
import {
|
|
17
17
|
GlasstraceSpanProcessor,
|
|
18
18
|
SdkError,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
performInit,
|
|
28
28
|
saveCachedConfig,
|
|
29
29
|
sendInitRequest
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-JKI4OCFV.js";
|
|
31
31
|
import {
|
|
32
32
|
isAnonymousMode,
|
|
33
33
|
isProductionDisabled,
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
import {
|
|
38
38
|
getOrCreateAnonKey,
|
|
39
39
|
readAnonKey
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-TWTWRJ25.js";
|
|
41
41
|
import {
|
|
42
42
|
deriveSessionId
|
|
43
43
|
} from "./chunk-X5MAXP5T.js";
|
|
@@ -3,10 +3,8 @@ import {
|
|
|
3
3
|
isMonorepoRoot,
|
|
4
4
|
parsePnpmWorkspaceYaml,
|
|
5
5
|
resolveProjectRoot
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-P22UQ2OJ.js";
|
|
9
|
-
import "./chunk-X5MAXP5T.js";
|
|
6
|
+
} from "./chunk-2M57EO6U.js";
|
|
7
|
+
import "./chunk-NB7GJE4S.js";
|
|
10
8
|
import "./chunk-NSBPE2FW.js";
|
|
11
9
|
export {
|
|
12
10
|
findNextJsApps,
|
|
@@ -14,4 +12,4 @@ export {
|
|
|
14
12
|
parsePnpmWorkspaceYaml,
|
|
15
13
|
resolveProjectRoot
|
|
16
14
|
};
|
|
17
|
-
//# sourceMappingURL=monorepo-
|
|
15
|
+
//# sourceMappingURL=monorepo-PFVNPQ6X.js.map
|
package/dist/node-entry.cjs
CHANGED
|
@@ -17495,6 +17495,208 @@ function sleep(ms, scheduler, signal) {
|
|
|
17495
17495
|
// src/mcp-runtime.ts
|
|
17496
17496
|
var import_node_crypto = require("node:crypto");
|
|
17497
17497
|
init_dist();
|
|
17498
|
+
|
|
17499
|
+
// src/atomic-write.ts
|
|
17500
|
+
function parentDir(filePath) {
|
|
17501
|
+
const lastSlash = filePath.lastIndexOf("/");
|
|
17502
|
+
const lastBackslash = filePath.lastIndexOf("\\");
|
|
17503
|
+
const lastSep = Math.max(lastSlash, lastBackslash);
|
|
17504
|
+
if (lastSep < 0) return ".";
|
|
17505
|
+
if (lastSep === 0) return filePath.slice(0, 1);
|
|
17506
|
+
return filePath.slice(0, lastSep);
|
|
17507
|
+
}
|
|
17508
|
+
var PARENT_FSYNC_SWALLOWED_CODES = /* @__PURE__ */ new Set([
|
|
17509
|
+
"EISDIR",
|
|
17510
|
+
"EINVAL",
|
|
17511
|
+
"EPERM",
|
|
17512
|
+
"ENOTSUP"
|
|
17513
|
+
]);
|
|
17514
|
+
function errnoCodeOf(err) {
|
|
17515
|
+
if (err === null || typeof err !== "object") return void 0;
|
|
17516
|
+
const code = err.code;
|
|
17517
|
+
return typeof code === "string" ? code : void 0;
|
|
17518
|
+
}
|
|
17519
|
+
function defaultTmpPath(targetPath) {
|
|
17520
|
+
return `${targetPath}.tmp`;
|
|
17521
|
+
}
|
|
17522
|
+
var fsPromisesCache;
|
|
17523
|
+
var fsSyncCache;
|
|
17524
|
+
async function loadFsPromises() {
|
|
17525
|
+
if (fsPromisesCache !== void 0) {
|
|
17526
|
+
if (fsPromisesCache === null) {
|
|
17527
|
+
throw new Error(
|
|
17528
|
+
"node:fs/promises is unavailable in this environment; atomicWriteFile cannot be used here."
|
|
17529
|
+
);
|
|
17530
|
+
}
|
|
17531
|
+
return fsPromisesCache;
|
|
17532
|
+
}
|
|
17533
|
+
try {
|
|
17534
|
+
fsPromisesCache = await import("node:fs/promises");
|
|
17535
|
+
return fsPromisesCache;
|
|
17536
|
+
} catch {
|
|
17537
|
+
fsPromisesCache = null;
|
|
17538
|
+
throw new Error(
|
|
17539
|
+
"node:fs/promises is unavailable in this environment; atomicWriteFile cannot be used here."
|
|
17540
|
+
);
|
|
17541
|
+
}
|
|
17542
|
+
}
|
|
17543
|
+
function loadFsSync() {
|
|
17544
|
+
if (fsSyncCache !== void 0) {
|
|
17545
|
+
if (fsSyncCache === null) {
|
|
17546
|
+
throw new Error(
|
|
17547
|
+
"node:fs is unavailable in this environment; atomicWriteFileSync cannot be used here."
|
|
17548
|
+
);
|
|
17549
|
+
}
|
|
17550
|
+
return fsSyncCache;
|
|
17551
|
+
}
|
|
17552
|
+
try {
|
|
17553
|
+
fsSyncCache = require("node:fs");
|
|
17554
|
+
return fsSyncCache;
|
|
17555
|
+
} catch {
|
|
17556
|
+
fsSyncCache = null;
|
|
17557
|
+
throw new Error(
|
|
17558
|
+
"node:fs is unavailable in this environment; atomicWriteFileSync cannot be used here."
|
|
17559
|
+
);
|
|
17560
|
+
}
|
|
17561
|
+
}
|
|
17562
|
+
async function atomicWriteFile(targetPath, payload, options = {}) {
|
|
17563
|
+
return atomicWriteFileWithTmp(targetPath, defaultTmpPath(targetPath), payload, options);
|
|
17564
|
+
}
|
|
17565
|
+
async function atomicWriteFileWithTmp(targetPath, tmpPath, payload, options = {}) {
|
|
17566
|
+
const mode = options.mode ?? 384;
|
|
17567
|
+
const encoding = options.encoding ?? "utf-8";
|
|
17568
|
+
const fsp = await loadFsPromises();
|
|
17569
|
+
let handle = null;
|
|
17570
|
+
try {
|
|
17571
|
+
if (typeof payload === "string") {
|
|
17572
|
+
await fsp.writeFile(tmpPath, payload, { encoding, mode });
|
|
17573
|
+
} else {
|
|
17574
|
+
await fsp.writeFile(tmpPath, payload, { mode });
|
|
17575
|
+
}
|
|
17576
|
+
await fsp.chmod(tmpPath, mode);
|
|
17577
|
+
handle = await fsp.open(tmpPath, "r");
|
|
17578
|
+
await handle.sync();
|
|
17579
|
+
await handle.close();
|
|
17580
|
+
handle = null;
|
|
17581
|
+
await fsp.rename(tmpPath, targetPath);
|
|
17582
|
+
} catch (err) {
|
|
17583
|
+
if (handle !== null) {
|
|
17584
|
+
try {
|
|
17585
|
+
await handle.close();
|
|
17586
|
+
} catch {
|
|
17587
|
+
}
|
|
17588
|
+
}
|
|
17589
|
+
await removeTmpResidueAsync(fsp, tmpPath);
|
|
17590
|
+
throw err;
|
|
17591
|
+
}
|
|
17592
|
+
await fsyncParentDirAsync(targetPath, fsp);
|
|
17593
|
+
}
|
|
17594
|
+
async function removeTmpResidueAsync(fsp, tmpPath) {
|
|
17595
|
+
try {
|
|
17596
|
+
await fsp.unlink(tmpPath);
|
|
17597
|
+
return;
|
|
17598
|
+
} catch (err) {
|
|
17599
|
+
const code = errnoCodeOf(err);
|
|
17600
|
+
if (code !== "EISDIR" && code !== "EPERM") {
|
|
17601
|
+
return;
|
|
17602
|
+
}
|
|
17603
|
+
}
|
|
17604
|
+
try {
|
|
17605
|
+
await fsp.rmdir(tmpPath);
|
|
17606
|
+
} catch {
|
|
17607
|
+
}
|
|
17608
|
+
}
|
|
17609
|
+
async function fsyncParentDirAsync(targetPath, fsp) {
|
|
17610
|
+
const parent = parentDir(targetPath);
|
|
17611
|
+
let handle = null;
|
|
17612
|
+
try {
|
|
17613
|
+
handle = await fsp.open(parent, "r");
|
|
17614
|
+
await handle.sync();
|
|
17615
|
+
} catch (err) {
|
|
17616
|
+
const code = errnoCodeOf(err);
|
|
17617
|
+
if (code !== void 0 && PARENT_FSYNC_SWALLOWED_CODES.has(code)) {
|
|
17618
|
+
return;
|
|
17619
|
+
}
|
|
17620
|
+
throw err;
|
|
17621
|
+
} finally {
|
|
17622
|
+
if (handle !== null) {
|
|
17623
|
+
try {
|
|
17624
|
+
await handle.close();
|
|
17625
|
+
} catch {
|
|
17626
|
+
}
|
|
17627
|
+
}
|
|
17628
|
+
}
|
|
17629
|
+
}
|
|
17630
|
+
function atomicWriteFileSync(targetPath, payload, options = {}) {
|
|
17631
|
+
atomicWriteFileSyncWithTmp(targetPath, defaultTmpPath(targetPath), payload, options);
|
|
17632
|
+
}
|
|
17633
|
+
function atomicWriteFileSyncWithTmp(targetPath, tmpPath, payload, options = {}) {
|
|
17634
|
+
const mode = options.mode ?? 384;
|
|
17635
|
+
const encoding = options.encoding ?? "utf-8";
|
|
17636
|
+
const fs4 = loadFsSync();
|
|
17637
|
+
let fd = null;
|
|
17638
|
+
try {
|
|
17639
|
+
if (typeof payload === "string") {
|
|
17640
|
+
fs4.writeFileSync(tmpPath, payload, { encoding, mode });
|
|
17641
|
+
} else {
|
|
17642
|
+
fs4.writeFileSync(tmpPath, payload, { mode });
|
|
17643
|
+
}
|
|
17644
|
+
fs4.chmodSync(tmpPath, mode);
|
|
17645
|
+
fd = fs4.openSync(tmpPath, "r");
|
|
17646
|
+
fs4.fsyncSync(fd);
|
|
17647
|
+
fs4.closeSync(fd);
|
|
17648
|
+
fd = null;
|
|
17649
|
+
fs4.renameSync(tmpPath, targetPath);
|
|
17650
|
+
} catch (err) {
|
|
17651
|
+
if (fd !== null) {
|
|
17652
|
+
try {
|
|
17653
|
+
fs4.closeSync(fd);
|
|
17654
|
+
} catch {
|
|
17655
|
+
}
|
|
17656
|
+
}
|
|
17657
|
+
removeTmpResidueSync(fs4, tmpPath);
|
|
17658
|
+
throw err;
|
|
17659
|
+
}
|
|
17660
|
+
fsyncParentDirSyncWithFs(targetPath, fs4);
|
|
17661
|
+
}
|
|
17662
|
+
function removeTmpResidueSync(fs4, tmpPath) {
|
|
17663
|
+
try {
|
|
17664
|
+
fs4.unlinkSync(tmpPath);
|
|
17665
|
+
return;
|
|
17666
|
+
} catch (err) {
|
|
17667
|
+
const code = errnoCodeOf(err);
|
|
17668
|
+
if (code !== "EISDIR" && code !== "EPERM") {
|
|
17669
|
+
return;
|
|
17670
|
+
}
|
|
17671
|
+
}
|
|
17672
|
+
try {
|
|
17673
|
+
fs4.rmdirSync(tmpPath);
|
|
17674
|
+
} catch {
|
|
17675
|
+
}
|
|
17676
|
+
}
|
|
17677
|
+
function fsyncParentDirSyncWithFs(targetPath, fs4) {
|
|
17678
|
+
const parent = parentDir(targetPath);
|
|
17679
|
+
let fd = null;
|
|
17680
|
+
try {
|
|
17681
|
+
fd = fs4.openSync(parent, "r");
|
|
17682
|
+
fs4.fsyncSync(fd);
|
|
17683
|
+
} catch (err) {
|
|
17684
|
+
const code = errnoCodeOf(err);
|
|
17685
|
+
if (code !== void 0 && PARENT_FSYNC_SWALLOWED_CODES.has(code)) {
|
|
17686
|
+
return;
|
|
17687
|
+
}
|
|
17688
|
+
throw err;
|
|
17689
|
+
} finally {
|
|
17690
|
+
if (fd !== null) {
|
|
17691
|
+
try {
|
|
17692
|
+
fs4.closeSync(fd);
|
|
17693
|
+
} catch {
|
|
17694
|
+
}
|
|
17695
|
+
}
|
|
17696
|
+
}
|
|
17697
|
+
}
|
|
17698
|
+
|
|
17699
|
+
// src/mcp-runtime.ts
|
|
17498
17700
|
var MCP_ENDPOINT = "https://api.glasstrace.dev/mcp";
|
|
17499
17701
|
var fsPathCache2;
|
|
17500
17702
|
async function loadFsPath2() {
|
|
@@ -17708,7 +17910,6 @@ async function refreshGenericMcpConfigAtRuntime(projectRoot, effective, anonKeyO
|
|
|
17708
17910
|
if (!modules) return { action: "absent" };
|
|
17709
17911
|
const dirPath = modules.path.join(projectRoot, GLASSTRACE_DIR2);
|
|
17710
17912
|
const configPath = modules.path.join(dirPath, MCP_CONFIG_FILE);
|
|
17711
|
-
const tmpPath = configPath + ".tmp";
|
|
17712
17913
|
let existing;
|
|
17713
17914
|
try {
|
|
17714
17915
|
existing = await modules.fs.readFile(configPath, "utf-8");
|
|
@@ -17725,18 +17926,12 @@ async function refreshGenericMcpConfigAtRuntime(projectRoot, effective, anonKeyO
|
|
|
17725
17926
|
}
|
|
17726
17927
|
const replacement = genericMcpConfigContent(MCP_ENDPOINT, effective.key);
|
|
17727
17928
|
try {
|
|
17728
|
-
await
|
|
17729
|
-
await modules.fs.chmod(tmpPath, 384);
|
|
17730
|
-
await modules.fs.rename(tmpPath, configPath);
|
|
17929
|
+
await atomicWriteFile(configPath, replacement, { mode: 384 });
|
|
17731
17930
|
await writeMcpMarker(projectRoot, {
|
|
17732
17931
|
credentialSource: effective.source,
|
|
17733
17932
|
credentialHash: identityFingerprint(effective.key)
|
|
17734
17933
|
});
|
|
17735
17934
|
} catch {
|
|
17736
|
-
try {
|
|
17737
|
-
await modules.fs.unlink(tmpPath);
|
|
17738
|
-
} catch {
|
|
17739
|
-
}
|
|
17740
17935
|
return { action: "preserved" };
|
|
17741
17936
|
}
|
|
17742
17937
|
emitRefreshNudge(effective.source);
|
|
@@ -17809,7 +18004,6 @@ async function saveCachedConfig(response, projectRoot) {
|
|
|
17809
18004
|
const root = projectRoot ?? process.cwd();
|
|
17810
18005
|
const dirPath = modules.path.join(root, GLASSTRACE_DIR3);
|
|
17811
18006
|
const configPath = modules.path.join(dirPath, CONFIG_FILE);
|
|
17812
|
-
const tmpPath = `${configPath}.tmp`;
|
|
17813
18007
|
try {
|
|
17814
18008
|
await modules.fs.mkdir(dirPath, { recursive: true, mode: 448 });
|
|
17815
18009
|
await modules.fs.chmod(dirPath, 448);
|
|
@@ -17817,20 +18011,10 @@ async function saveCachedConfig(response, projectRoot) {
|
|
|
17817
18011
|
response,
|
|
17818
18012
|
cachedAt: Date.now()
|
|
17819
18013
|
};
|
|
17820
|
-
await
|
|
18014
|
+
await atomicWriteFile(configPath, JSON.stringify(cached2), {
|
|
17821
18015
|
encoding: "utf-8",
|
|
17822
18016
|
mode: 384
|
|
17823
18017
|
});
|
|
17824
|
-
try {
|
|
17825
|
-
await modules.fs.chmod(tmpPath, 384);
|
|
17826
|
-
await modules.fs.rename(tmpPath, configPath);
|
|
17827
|
-
} catch (renameErr) {
|
|
17828
|
-
try {
|
|
17829
|
-
await modules.fs.unlink(tmpPath);
|
|
17830
|
-
} catch {
|
|
17831
|
-
}
|
|
17832
|
-
throw renameErr;
|
|
17833
|
-
}
|
|
17834
18018
|
await modules.fs.chmod(configPath, 384);
|
|
17835
18019
|
} catch (err) {
|
|
17836
18020
|
console.warn(
|
|
@@ -18109,6 +18293,128 @@ init_esm();
|
|
|
18109
18293
|
init_dist();
|
|
18110
18294
|
init_console_capture();
|
|
18111
18295
|
init_error_nudge();
|
|
18296
|
+
|
|
18297
|
+
// src/error-response-body.ts
|
|
18298
|
+
var ERROR_RESPONSE_BODY_MAX_BYTES = 4096;
|
|
18299
|
+
var ERROR_RESPONSE_BODY_TRUNCATION_MARKER = "...[truncated]";
|
|
18300
|
+
var REDACTED = "[REDACTED]";
|
|
18301
|
+
var ERROR_STATUS_MIN = 400;
|
|
18302
|
+
var ERROR_STATUS_MAX = 599;
|
|
18303
|
+
function isHttpErrorStatus(status) {
|
|
18304
|
+
let numeric;
|
|
18305
|
+
if (typeof status === "number") {
|
|
18306
|
+
numeric = status;
|
|
18307
|
+
} else if (typeof status === "string" && status.length > 0) {
|
|
18308
|
+
numeric = Number(status);
|
|
18309
|
+
} else {
|
|
18310
|
+
return false;
|
|
18311
|
+
}
|
|
18312
|
+
if (!Number.isFinite(numeric)) return false;
|
|
18313
|
+
return numeric >= ERROR_STATUS_MIN && numeric <= ERROR_STATUS_MAX;
|
|
18314
|
+
}
|
|
18315
|
+
var REDACTION_PATTERNS = [
|
|
18316
|
+
// Order matters: redact specific token shapes BEFORE the generic
|
|
18317
|
+
// key=value catcher so a literal `Bearer eyJ…` collapses into a single
|
|
18318
|
+
// [REDACTED] and the JWT regex does not separately match the suffix.
|
|
18319
|
+
{
|
|
18320
|
+
name: "bearer",
|
|
18321
|
+
// Case-insensitive on the scheme: HTTP frameworks and proxies
|
|
18322
|
+
// round-trip the auth scheme with inconsistent casing
|
|
18323
|
+
// (`Bearer`, `bearer`, `BEARER`), and a real token leaks just as
|
|
18324
|
+
// badly under any of them.
|
|
18325
|
+
pattern: /\bBearer\s+[A-Za-z0-9._\-+/=]+/gi
|
|
18326
|
+
},
|
|
18327
|
+
{
|
|
18328
|
+
name: "jwt",
|
|
18329
|
+
// Three base64url segments separated by dots. Real JWTs encode at
|
|
18330
|
+
// minimum a small JSON header in the first segment, which alone is
|
|
18331
|
+
// typically ≥10 chars after base64url; a 16-char floor avoids false
|
|
18332
|
+
// positives on dotted text like a stack-trace frame
|
|
18333
|
+
// (`react.dom.server`) while still catching every real JWT we have
|
|
18334
|
+
// seen in the wild. Anchored with word boundaries on both sides so
|
|
18335
|
+
// a 3-dot semantic version like "next@15.4.1.2" does not match.
|
|
18336
|
+
pattern: /\b[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g
|
|
18337
|
+
},
|
|
18338
|
+
{
|
|
18339
|
+
name: "glasstrace-api-key",
|
|
18340
|
+
// gt_dev_* and gt_anon_* keys are >=24 chars of [A-Za-z0-9].
|
|
18341
|
+
pattern: /\bgt_(?:dev|anon)_[A-Za-z0-9]{16,}\b/g
|
|
18342
|
+
},
|
|
18343
|
+
{
|
|
18344
|
+
name: "aws-access-key",
|
|
18345
|
+
// 20-char prefix-fixed identifier.
|
|
18346
|
+
pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g
|
|
18347
|
+
},
|
|
18348
|
+
{
|
|
18349
|
+
name: "key-value-secret-quoted",
|
|
18350
|
+
// Quoted-string variant: (key) [:=] "<value>". The value runs to
|
|
18351
|
+
// the next unescaped closing quote so a multi-word secret like
|
|
18352
|
+
// `password="my secret phrase"` is fully consumed instead of
|
|
18353
|
+
// splitting at the first space and leaving the tail visible.
|
|
18354
|
+
// The leading `(?<![A-Za-z0-9_])` prevents matching inside
|
|
18355
|
+
// identifiers like `passwordless`. The trailing `"?` after the
|
|
18356
|
+
// keyword absorbs the closing quote in JSON-style `"apikey":
|
|
18357
|
+
// "value"` so the colon is still seen as the separator.
|
|
18358
|
+
pattern: /(?<![A-Za-z0-9_])(?:api[_-]?key|apikey|secret|password|token)"?\s*[:=]\s*"(?:[^"\\]|\\.)*"/gi
|
|
18359
|
+
},
|
|
18360
|
+
{
|
|
18361
|
+
name: "key-value-secret-bare",
|
|
18362
|
+
// Unquoted variant: (key) [:=] <bare-value>. The bare value
|
|
18363
|
+
// capture stops at common JSON/text delimiters so we redact only
|
|
18364
|
+
// the value, not surrounding structure. Listed AFTER the quoted
|
|
18365
|
+
// variant so a quoted value's surrounding `"` are consumed by
|
|
18366
|
+
// the first pattern and we never fall through here for a quoted
|
|
18367
|
+
// secret.
|
|
18368
|
+
pattern: /(?<![A-Za-z0-9_])(?:api[_-]?key|apikey|secret|password|token)"?\s*[:=]\s*[^\s,;}\]"]+/gi
|
|
18369
|
+
}
|
|
18370
|
+
];
|
|
18371
|
+
function sanitizeErrorResponseBody(body) {
|
|
18372
|
+
let out = body;
|
|
18373
|
+
for (const { pattern } of REDACTION_PATTERNS) {
|
|
18374
|
+
out = out.replace(pattern, REDACTED);
|
|
18375
|
+
}
|
|
18376
|
+
return out;
|
|
18377
|
+
}
|
|
18378
|
+
function truncateErrorResponseBody(body) {
|
|
18379
|
+
const encoder = new TextEncoder();
|
|
18380
|
+
const encoded = encoder.encode(body);
|
|
18381
|
+
if (encoded.byteLength <= ERROR_RESPONSE_BODY_MAX_BYTES) {
|
|
18382
|
+
return body;
|
|
18383
|
+
}
|
|
18384
|
+
let cut = ERROR_RESPONSE_BODY_MAX_BYTES;
|
|
18385
|
+
let scan = cut - 1;
|
|
18386
|
+
while (scan >= 0 && (encoded[scan] & 192) === 128) {
|
|
18387
|
+
scan -= 1;
|
|
18388
|
+
}
|
|
18389
|
+
if (scan >= 0) {
|
|
18390
|
+
const leading = encoded[scan];
|
|
18391
|
+
let expected = 1;
|
|
18392
|
+
if ((leading & 128) === 0) {
|
|
18393
|
+
expected = 1;
|
|
18394
|
+
} else if ((leading & 224) === 192) {
|
|
18395
|
+
expected = 2;
|
|
18396
|
+
} else if ((leading & 240) === 224) {
|
|
18397
|
+
expected = 3;
|
|
18398
|
+
} else if ((leading & 248) === 240) {
|
|
18399
|
+
expected = 4;
|
|
18400
|
+
}
|
|
18401
|
+
if (scan + expected > cut) {
|
|
18402
|
+
cut = scan;
|
|
18403
|
+
}
|
|
18404
|
+
}
|
|
18405
|
+
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
18406
|
+
const sliced = encoded.subarray(0, cut);
|
|
18407
|
+
const decoded = decoder.decode(sliced);
|
|
18408
|
+
return decoded + ERROR_RESPONSE_BODY_TRUNCATION_MARKER;
|
|
18409
|
+
}
|
|
18410
|
+
function prepareErrorResponseBody(body) {
|
|
18411
|
+
if (body.length === 0) return null;
|
|
18412
|
+
if (body.trim().length === 0) return null;
|
|
18413
|
+
const sanitized = sanitizeErrorResponseBody(body);
|
|
18414
|
+
return truncateErrorResponseBody(sanitized);
|
|
18415
|
+
}
|
|
18416
|
+
|
|
18417
|
+
// src/enriching-exporter.ts
|
|
18112
18418
|
var ATTR2 = GLASSTRACE_ATTRIBUTE_NAMES;
|
|
18113
18419
|
var API_KEY_PENDING = "pending";
|
|
18114
18420
|
var MAX_PENDING_SPANS = 1024;
|
|
@@ -18336,7 +18642,14 @@ var GlasstraceExporter = class {
|
|
|
18336
18642
|
if (this.getConfig().errorResponseBodies) {
|
|
18337
18643
|
const responseBody = attrs["glasstrace.internal.response_body"];
|
|
18338
18644
|
if (typeof responseBody === "string") {
|
|
18339
|
-
extra[ATTR2.
|
|
18645
|
+
const enrichedStatus = extra[ATTR2.HTTP_STATUS_CODE];
|
|
18646
|
+
const effectiveStatus = typeof enrichedStatus === "number" ? enrichedStatus : statusCode;
|
|
18647
|
+
if (isHttpErrorStatus(effectiveStatus)) {
|
|
18648
|
+
const prepared = prepareErrorResponseBody(responseBody);
|
|
18649
|
+
if (prepared !== null) {
|
|
18650
|
+
extra[ATTR2.ERROR_RESPONSE_BODY] = prepared;
|
|
18651
|
+
}
|
|
18652
|
+
}
|
|
18340
18653
|
}
|
|
18341
18654
|
}
|
|
18342
18655
|
const spanAny = span;
|
|
@@ -22158,12 +22471,10 @@ function writeStateNow() {
|
|
|
22158
22471
|
};
|
|
22159
22472
|
const dir = (0, import_node_path.join)(_projectRoot, ".glasstrace");
|
|
22160
22473
|
const filePath = (0, import_node_path.join)(dir, "runtime-state.json");
|
|
22161
|
-
const tmpPath = (0, import_node_path.join)(dir, "runtime-state.json.tmp");
|
|
22162
22474
|
(0, import_node_fs.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
22163
|
-
(
|
|
22475
|
+
atomicWriteFileSync(filePath, JSON.stringify(runtimeState, null, 2) + "\n", {
|
|
22164
22476
|
mode: 384
|
|
22165
22477
|
});
|
|
22166
|
-
(0, import_node_fs.renameSync)(tmpPath, filePath);
|
|
22167
22478
|
} catch (err) {
|
|
22168
22479
|
sdkLog(
|
|
22169
22480
|
"warn",
|
|
@@ -22202,7 +22513,7 @@ function registerGlasstrace(options) {
|
|
|
22202
22513
|
setCoreState(CoreState.REGISTERING);
|
|
22203
22514
|
startRuntimeStateWriter({
|
|
22204
22515
|
projectRoot: process.cwd(),
|
|
22205
|
-
sdkVersion: "1.1.
|
|
22516
|
+
sdkVersion: "1.1.3"
|
|
22206
22517
|
});
|
|
22207
22518
|
const config2 = resolveConfig(options);
|
|
22208
22519
|
if (config2.verbose) {
|
|
@@ -22368,8 +22679,8 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
22368
22679
|
if (config2.verbose) {
|
|
22369
22680
|
console.info("[glasstrace] Background init firing.");
|
|
22370
22681
|
}
|
|
22371
|
-
const healthReport = collectHealthReport("1.1.
|
|
22372
|
-
const initResult = await performInit(config2, anonKeyForInit, "1.1.
|
|
22682
|
+
const healthReport = collectHealthReport("1.1.3");
|
|
22683
|
+
const initResult = await performInit(config2, anonKeyForInit, "1.1.3", healthReport);
|
|
22373
22684
|
if (generation !== registrationGeneration) return;
|
|
22374
22685
|
const currentState = getCoreState();
|
|
22375
22686
|
if (currentState === CoreState.SHUTTING_DOWN || currentState === CoreState.SHUTDOWN) {
|
|
@@ -22392,7 +22703,7 @@ async function backgroundInit(config2, anonKeyForInit, generation) {
|
|
|
22392
22703
|
}
|
|
22393
22704
|
maybeInstallConsoleCapture();
|
|
22394
22705
|
if (didLastInitSucceed()) {
|
|
22395
|
-
startHeartbeat(config2, anonKeyForInit, "1.1.
|
|
22706
|
+
startHeartbeat(config2, anonKeyForInit, "1.1.3", generation, (newApiKey, accountId) => {
|
|
22396
22707
|
setAuthState(AuthState.CLAIMING);
|
|
22397
22708
|
emitLifecycleEvent("auth:claim_started", { accountId });
|
|
22398
22709
|
setResolvedApiKey(newApiKey);
|