brakit 0.8.3 → 0.8.4
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/api.js +13 -14
- package/dist/bin/brakit.js +95 -70
- package/dist/mcp/server.js +1 -1
- package/dist/runtime/index.js +214 -21
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -299,6 +299,7 @@ var FindingStore = class {
|
|
|
299
299
|
|
|
300
300
|
// src/detect/project.ts
|
|
301
301
|
import { readFile as readFile2 } from "fs/promises";
|
|
302
|
+
import { existsSync as existsSync4 } from "fs";
|
|
302
303
|
import { join } from "path";
|
|
303
304
|
var FRAMEWORKS = [
|
|
304
305
|
{ name: "nextjs", dep: "next", devCmd: "next dev", bin: "next", defaultPort: 3e3, devArgs: ["dev", "--port"] },
|
|
@@ -312,19 +313,11 @@ async function detectProject(rootDir) {
|
|
|
312
313
|
const raw = await readFile2(pkgPath, "utf-8");
|
|
313
314
|
const pkg = JSON.parse(raw);
|
|
314
315
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (allDeps[f.dep]) {
|
|
321
|
-
framework = f.name;
|
|
322
|
-
devCommand = f.devCmd;
|
|
323
|
-
devBin = join(rootDir, "node_modules", ".bin", f.bin);
|
|
324
|
-
defaultPort = f.defaultPort;
|
|
325
|
-
break;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
316
|
+
const framework = detectFrameworkFromDeps(allDeps);
|
|
317
|
+
const matched = FRAMEWORKS.find((f) => f.name === framework);
|
|
318
|
+
const devCommand = matched?.devCmd ?? "";
|
|
319
|
+
const devBin = matched ? join(rootDir, "node_modules", ".bin", matched.bin) : "";
|
|
320
|
+
const defaultPort = matched?.defaultPort ?? 3e3;
|
|
328
321
|
const packageManager = await detectPackageManager(rootDir);
|
|
329
322
|
return { framework, devCommand, devBin, defaultPort, packageManager };
|
|
330
323
|
}
|
|
@@ -336,6 +329,12 @@ async function detectPackageManager(rootDir) {
|
|
|
336
329
|
if (await fileExists(join(rootDir, "package-lock.json"))) return "npm";
|
|
337
330
|
return "unknown";
|
|
338
331
|
}
|
|
332
|
+
function detectFrameworkFromDeps(allDeps) {
|
|
333
|
+
for (const f of FRAMEWORKS) {
|
|
334
|
+
if (allDeps[f.dep]) return f.name;
|
|
335
|
+
}
|
|
336
|
+
return "unknown";
|
|
337
|
+
}
|
|
339
338
|
|
|
340
339
|
// src/instrument/adapter-registry.ts
|
|
341
340
|
var AdapterRegistry = class {
|
|
@@ -2063,7 +2062,7 @@ var AnalysisEngine = class {
|
|
|
2063
2062
|
};
|
|
2064
2063
|
|
|
2065
2064
|
// src/index.ts
|
|
2066
|
-
var VERSION = "0.8.
|
|
2065
|
+
var VERSION = "0.8.4";
|
|
2067
2066
|
export {
|
|
2068
2067
|
AdapterRegistry,
|
|
2069
2068
|
AnalysisEngine,
|
package/dist/bin/brakit.js
CHANGED
|
@@ -82,7 +82,7 @@ var init_mcp = __esm({
|
|
|
82
82
|
"src/constants/mcp.ts"() {
|
|
83
83
|
"use strict";
|
|
84
84
|
MCP_SERVER_NAME = "brakit";
|
|
85
|
-
MCP_SERVER_VERSION = "0.8.
|
|
85
|
+
MCP_SERVER_VERSION = "0.8.4";
|
|
86
86
|
INITIAL_DISCOVERY_TIMEOUT_MS = 5e3;
|
|
87
87
|
LAZY_DISCOVERY_TIMEOUT_MS = 2e3;
|
|
88
88
|
CLIENT_FETCH_TIMEOUT_MS = 1e4;
|
|
@@ -118,6 +118,13 @@ var init_severity = __esm({
|
|
|
118
118
|
}
|
|
119
119
|
});
|
|
120
120
|
|
|
121
|
+
// src/constants/telemetry.ts
|
|
122
|
+
var init_telemetry = __esm({
|
|
123
|
+
"src/constants/telemetry.ts"() {
|
|
124
|
+
"use strict";
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
121
128
|
// src/constants/index.ts
|
|
122
129
|
var init_constants = __esm({
|
|
123
130
|
"src/constants/index.ts"() {
|
|
@@ -132,6 +139,7 @@ var init_constants = __esm({
|
|
|
132
139
|
init_mcp();
|
|
133
140
|
init_encoding();
|
|
134
141
|
init_severity();
|
|
142
|
+
init_telemetry();
|
|
135
143
|
}
|
|
136
144
|
});
|
|
137
145
|
|
|
@@ -244,10 +252,10 @@ var init_client = __esm({
|
|
|
244
252
|
});
|
|
245
253
|
|
|
246
254
|
// src/mcp/discovery.ts
|
|
247
|
-
import { readFileSync as readFileSync3, existsSync as
|
|
255
|
+
import { readFileSync as readFileSync3, existsSync as existsSync5, readdirSync, statSync } from "fs";
|
|
248
256
|
import { resolve as resolve5, dirname } from "path";
|
|
249
257
|
function readPort(portPath) {
|
|
250
|
-
if (!
|
|
258
|
+
if (!existsSync5(portPath)) return null;
|
|
251
259
|
const raw = readFileSync3(portPath, "utf-8").trim();
|
|
252
260
|
const port = parseInt(raw, 10);
|
|
253
261
|
return isNaN(port) || port < 1 || port > 65535 ? null : port;
|
|
@@ -1019,6 +1027,7 @@ init_finding_id();
|
|
|
1019
1027
|
|
|
1020
1028
|
// src/detect/project.ts
|
|
1021
1029
|
import { readFile as readFile2 } from "fs/promises";
|
|
1030
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1022
1031
|
import { join } from "path";
|
|
1023
1032
|
var FRAMEWORKS = [
|
|
1024
1033
|
{ name: "nextjs", dep: "next", devCmd: "next dev", bin: "next", defaultPort: 3e3, devArgs: ["dev", "--port"] },
|
|
@@ -1032,19 +1041,11 @@ async function detectProject(rootDir) {
|
|
|
1032
1041
|
const raw = await readFile2(pkgPath, "utf-8");
|
|
1033
1042
|
const pkg = JSON.parse(raw);
|
|
1034
1043
|
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
if (allDeps[f.dep]) {
|
|
1041
|
-
framework = f.name;
|
|
1042
|
-
devCommand = f.devCmd;
|
|
1043
|
-
devBin = join(rootDir, "node_modules", ".bin", f.bin);
|
|
1044
|
-
defaultPort = f.defaultPort;
|
|
1045
|
-
break;
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1044
|
+
const framework = detectFrameworkFromDeps(allDeps);
|
|
1045
|
+
const matched = FRAMEWORKS.find((f) => f.name === framework);
|
|
1046
|
+
const devCommand = matched?.devCmd ?? "";
|
|
1047
|
+
const devBin = matched ? join(rootDir, "node_modules", ".bin", matched.bin) : "";
|
|
1048
|
+
const defaultPort = matched?.defaultPort ?? 3e3;
|
|
1048
1049
|
const packageManager = await detectPackageManager(rootDir);
|
|
1049
1050
|
return { framework, devCommand, devBin, defaultPort, packageManager };
|
|
1050
1051
|
}
|
|
@@ -1056,6 +1057,12 @@ async function detectPackageManager(rootDir) {
|
|
|
1056
1057
|
if (await fileExists(join(rootDir, "package-lock.json"))) return "npm";
|
|
1057
1058
|
return "unknown";
|
|
1058
1059
|
}
|
|
1060
|
+
function detectFrameworkFromDeps(allDeps) {
|
|
1061
|
+
for (const f of FRAMEWORKS) {
|
|
1062
|
+
if (allDeps[f.dep]) return f.name;
|
|
1063
|
+
}
|
|
1064
|
+
return "unknown";
|
|
1065
|
+
}
|
|
1059
1066
|
|
|
1060
1067
|
// src/analysis/rules/patterns.ts
|
|
1061
1068
|
var SECRET_KEYS = /^(password|passwd|secret|api_key|apiKey|api_secret|apiSecret|private_key|privateKey|client_secret|clientSecret)$/;
|
|
@@ -1593,11 +1600,58 @@ init_endpoint();
|
|
|
1593
1600
|
init_thresholds();
|
|
1594
1601
|
|
|
1595
1602
|
// src/index.ts
|
|
1596
|
-
var VERSION = "0.8.
|
|
1603
|
+
var VERSION = "0.8.4";
|
|
1597
1604
|
|
|
1598
1605
|
// src/cli/commands/install.ts
|
|
1606
|
+
init_constants();
|
|
1607
|
+
|
|
1608
|
+
// src/cli/templates.ts
|
|
1599
1609
|
var IMPORT_LINE = `import "brakit";`;
|
|
1600
1610
|
var IMPORT_MARKER = "brakit";
|
|
1611
|
+
var CREATED_FILES = [
|
|
1612
|
+
"src/instrumentation.ts",
|
|
1613
|
+
"instrumentation.ts",
|
|
1614
|
+
"server/plugins/brakit.ts"
|
|
1615
|
+
];
|
|
1616
|
+
var ENTRY_CANDIDATES = [
|
|
1617
|
+
"src/index.ts",
|
|
1618
|
+
"src/server.ts",
|
|
1619
|
+
"src/app.ts",
|
|
1620
|
+
"src/index.js",
|
|
1621
|
+
"src/server.js",
|
|
1622
|
+
"src/app.js",
|
|
1623
|
+
"server.ts",
|
|
1624
|
+
"app.ts",
|
|
1625
|
+
"index.ts",
|
|
1626
|
+
"server.js",
|
|
1627
|
+
"app.js",
|
|
1628
|
+
"index.js"
|
|
1629
|
+
];
|
|
1630
|
+
var BRAKIT_TEMPLATES = {
|
|
1631
|
+
/** Next.js instrumentation.ts — standalone file created by install */
|
|
1632
|
+
nextjs: [
|
|
1633
|
+
`export async function register() {`,
|
|
1634
|
+
` if (process.env.NODE_ENV !== "production") {`,
|
|
1635
|
+
` try { await import("brakit"); } catch {}`,
|
|
1636
|
+
` }`,
|
|
1637
|
+
`}`
|
|
1638
|
+
].join("\n"),
|
|
1639
|
+
/** Nuxt server/plugins/brakit.ts — standalone file created by install */
|
|
1640
|
+
nuxt: `import "brakit";`
|
|
1641
|
+
};
|
|
1642
|
+
var ALL_TEMPLATES = Object.values(BRAKIT_TEMPLATES);
|
|
1643
|
+
function normalize(content) {
|
|
1644
|
+
return content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).join("\n");
|
|
1645
|
+
}
|
|
1646
|
+
function isExactBrakitTemplate(fileContent) {
|
|
1647
|
+
const normalizedFile = normalize(fileContent);
|
|
1648
|
+
if (!normalizedFile) return false;
|
|
1649
|
+
return ALL_TEMPLATES.some(
|
|
1650
|
+
(template) => normalize(template) === normalizedFile
|
|
1651
|
+
);
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// src/cli/commands/install.ts
|
|
1601
1655
|
var install_default = defineCommand({
|
|
1602
1656
|
meta: {
|
|
1603
1657
|
name: "brakit install",
|
|
@@ -1662,6 +1716,7 @@ var install_default = defineCommand({
|
|
|
1662
1716
|
} else {
|
|
1663
1717
|
printManualInstructions(project.framework);
|
|
1664
1718
|
}
|
|
1719
|
+
await ensureGitignoreEntry(rootDir, METRICS_DIR);
|
|
1665
1720
|
const mcpResult = await setupMcp(rootDir);
|
|
1666
1721
|
if (mcpResult === "created" || mcpResult === "updated") {
|
|
1667
1722
|
console.log(pc.green(" \u2713 Configured MCP for Claude Code / Cursor"));
|
|
@@ -1690,6 +1745,7 @@ async function installPackage(rootDir, pm) {
|
|
|
1690
1745
|
execSync(cmd, { cwd: rootDir, stdio: "pipe" });
|
|
1691
1746
|
} catch {
|
|
1692
1747
|
console.warn(pc.yellow(` \u26A0 Failed to run "${cmd}". Install brakit manually.`));
|
|
1748
|
+
return false;
|
|
1693
1749
|
}
|
|
1694
1750
|
return true;
|
|
1695
1751
|
}
|
|
@@ -1716,14 +1772,7 @@ async function setupNextjs(rootDir) {
|
|
|
1716
1772
|
}
|
|
1717
1773
|
return { action: "manual", file: relPath };
|
|
1718
1774
|
}
|
|
1719
|
-
const content =
|
|
1720
|
-
`export async function register() {`,
|
|
1721
|
-
` if (process.env.NODE_ENV !== "production") {`,
|
|
1722
|
-
` try { await import("brakit"); } catch {}`,
|
|
1723
|
-
` }`,
|
|
1724
|
-
`}`,
|
|
1725
|
-
``
|
|
1726
|
-
].join("\n");
|
|
1775
|
+
const content = BRAKIT_TEMPLATES.nextjs + "\n";
|
|
1727
1776
|
await writeFile3(absPath, content);
|
|
1728
1777
|
return { action: "created", file: relPath, content };
|
|
1729
1778
|
}
|
|
@@ -1737,8 +1786,7 @@ async function setupNuxt(rootDir) {
|
|
|
1737
1786
|
}
|
|
1738
1787
|
return { action: "manual", file: relPath };
|
|
1739
1788
|
}
|
|
1740
|
-
const content =
|
|
1741
|
-
`;
|
|
1789
|
+
const content = BRAKIT_TEMPLATES.nuxt + "\n";
|
|
1742
1790
|
const dir = join2(rootDir, "server/plugins");
|
|
1743
1791
|
const { mkdirSync: mkdirSync3 } = await import("fs");
|
|
1744
1792
|
mkdirSync3(dir, { recursive: true });
|
|
@@ -1759,20 +1807,6 @@ ${content}`);
|
|
|
1759
1807
|
}
|
|
1760
1808
|
return { action: "manual", file: null };
|
|
1761
1809
|
}
|
|
1762
|
-
var ENTRY_CANDIDATES = [
|
|
1763
|
-
"src/index.ts",
|
|
1764
|
-
"src/server.ts",
|
|
1765
|
-
"src/app.ts",
|
|
1766
|
-
"src/index.js",
|
|
1767
|
-
"src/server.js",
|
|
1768
|
-
"src/app.js",
|
|
1769
|
-
"server.ts",
|
|
1770
|
-
"app.ts",
|
|
1771
|
-
"index.ts",
|
|
1772
|
-
"server.js",
|
|
1773
|
-
"app.js",
|
|
1774
|
-
"index.js"
|
|
1775
|
-
];
|
|
1776
1810
|
async function setupGeneric(rootDir) {
|
|
1777
1811
|
try {
|
|
1778
1812
|
const pkgRaw = await readFile3(join2(rootDir, "package.json"), "utf-8");
|
|
@@ -1804,24 +1838,24 @@ async function setupMcp(rootDir) {
|
|
|
1804
1838
|
if (config?.mcpServers?.brakit) return "exists";
|
|
1805
1839
|
config.mcpServers = { ...config.mcpServers, ...MCP_CONFIG.mcpServers };
|
|
1806
1840
|
await writeFile3(mcpPath, JSON.stringify(config, null, 2) + "\n");
|
|
1807
|
-
await
|
|
1841
|
+
await ensureGitignoreEntry(rootDir, ".mcp.json");
|
|
1808
1842
|
return "updated";
|
|
1809
1843
|
} catch {
|
|
1810
1844
|
}
|
|
1811
1845
|
}
|
|
1812
1846
|
await writeFile3(mcpPath, JSON.stringify(MCP_CONFIG, null, 2) + "\n");
|
|
1813
|
-
await
|
|
1847
|
+
await ensureGitignoreEntry(rootDir, ".mcp.json");
|
|
1814
1848
|
return "created";
|
|
1815
1849
|
}
|
|
1816
|
-
async function
|
|
1850
|
+
async function ensureGitignoreEntry(rootDir, entry) {
|
|
1817
1851
|
const gitignorePath = join2(rootDir, ".gitignore");
|
|
1818
1852
|
try {
|
|
1819
1853
|
if (await fileExists(gitignorePath)) {
|
|
1820
1854
|
const content = await readFile3(gitignorePath, "utf-8");
|
|
1821
|
-
if (content.split("\n").some((l) => l.trim() ===
|
|
1822
|
-
await writeFile3(gitignorePath, content.trimEnd() + "\n
|
|
1855
|
+
if (content.split("\n").some((l) => l.trim() === entry)) return;
|
|
1856
|
+
await writeFile3(gitignorePath, content.trimEnd() + "\n" + entry + "\n");
|
|
1823
1857
|
} else {
|
|
1824
|
-
await writeFile3(gitignorePath, "
|
|
1858
|
+
await writeFile3(gitignorePath, entry + "\n");
|
|
1825
1859
|
}
|
|
1826
1860
|
} catch {
|
|
1827
1861
|
}
|
|
@@ -1850,27 +1884,10 @@ import { readFile as readFile4, writeFile as writeFile4, unlink, rm } from "fs/p
|
|
|
1850
1884
|
import { execSync as execSync2 } from "child_process";
|
|
1851
1885
|
import pc2 from "picocolors";
|
|
1852
1886
|
init_constants();
|
|
1853
|
-
var IMPORT_LINE2 = `import "brakit";`;
|
|
1854
|
-
var CREATED_FILES = [
|
|
1855
|
-
"src/instrumentation.ts",
|
|
1856
|
-
"instrumentation.ts",
|
|
1857
|
-
"server/plugins/brakit.ts"
|
|
1858
|
-
];
|
|
1859
1887
|
var PREPENDED_FILES = [
|
|
1860
1888
|
"app/entry.server.tsx",
|
|
1861
1889
|
"app/entry.server.ts",
|
|
1862
|
-
|
|
1863
|
-
"src/server.ts",
|
|
1864
|
-
"src/app.ts",
|
|
1865
|
-
"src/index.js",
|
|
1866
|
-
"src/server.js",
|
|
1867
|
-
"src/app.js",
|
|
1868
|
-
"server.ts",
|
|
1869
|
-
"app.ts",
|
|
1870
|
-
"index.ts",
|
|
1871
|
-
"server.js",
|
|
1872
|
-
"app.js",
|
|
1873
|
-
"index.js"
|
|
1890
|
+
...ENTRY_CANDIDATES
|
|
1874
1891
|
];
|
|
1875
1892
|
var uninstall_default = defineCommand2({
|
|
1876
1893
|
meta: {
|
|
@@ -1902,14 +1919,22 @@ var uninstall_default = defineCommand2({
|
|
|
1902
1919
|
if (!await fileExists(absPath)) continue;
|
|
1903
1920
|
const content = await readFile4(absPath, "utf-8");
|
|
1904
1921
|
if (!content.includes("brakit")) continue;
|
|
1905
|
-
|
|
1906
|
-
const allBrakit = lines.every((l) => l.includes("brakit") || l.includes("register") || l.includes("import") || l.includes("export") || l.includes("try") || l.includes("catch") || l.includes("process.env") || l.includes("{") || l.includes("}"));
|
|
1907
|
-
if (allBrakit) {
|
|
1922
|
+
if (isExactBrakitTemplate(content)) {
|
|
1908
1923
|
await unlink(absPath);
|
|
1909
1924
|
console.log(pc2.green(` \u2713 Removed ${relPath}`));
|
|
1910
1925
|
removed = true;
|
|
1911
1926
|
break;
|
|
1912
1927
|
}
|
|
1928
|
+
const lines = content.split("\n");
|
|
1929
|
+
const cleaned = lines.filter(
|
|
1930
|
+
(line) => !line.includes('import("brakit")') && !line.includes('import "brakit"')
|
|
1931
|
+
);
|
|
1932
|
+
if (cleaned.length < lines.length) {
|
|
1933
|
+
await writeFile4(absPath, cleaned.join("\n"));
|
|
1934
|
+
console.log(pc2.green(` \u2713 Removed brakit lines from ${relPath}`));
|
|
1935
|
+
removed = true;
|
|
1936
|
+
break;
|
|
1937
|
+
}
|
|
1913
1938
|
}
|
|
1914
1939
|
if (!removed) {
|
|
1915
1940
|
const candidates = [...PREPENDED_FILES];
|
|
@@ -1923,8 +1948,8 @@ var uninstall_default = defineCommand2({
|
|
|
1923
1948
|
const absPath = join3(rootDir, relPath);
|
|
1924
1949
|
if (!await fileExists(absPath)) continue;
|
|
1925
1950
|
const content = await readFile4(absPath, "utf-8");
|
|
1926
|
-
if (!content.includes(
|
|
1927
|
-
const updated = content.split("\n").filter((line) => line.trim() !==
|
|
1951
|
+
if (!content.includes(IMPORT_LINE)) continue;
|
|
1952
|
+
const updated = content.split("\n").filter((line) => line.trim() !== IMPORT_LINE.trim()).join("\n");
|
|
1928
1953
|
await writeFile4(absPath, updated);
|
|
1929
1954
|
console.log(pc2.green(` \u2713 Removed brakit import from ${relPath}`));
|
|
1930
1955
|
removed = true;
|
package/dist/mcp/server.js
CHANGED
|
@@ -22,7 +22,7 @@ var DASHBOARD_API_FINDINGS = "/__brakit/api/findings";
|
|
|
22
22
|
|
|
23
23
|
// src/constants/mcp.ts
|
|
24
24
|
var MCP_SERVER_NAME = "brakit";
|
|
25
|
-
var MCP_SERVER_VERSION = "0.8.
|
|
25
|
+
var MCP_SERVER_VERSION = "0.8.4";
|
|
26
26
|
var INITIAL_DISCOVERY_TIMEOUT_MS = 5e3;
|
|
27
27
|
var LAZY_DISCOVERY_TIMEOUT_MS = 2e3;
|
|
28
28
|
var CLIENT_FETCH_TIMEOUT_MS = 1e4;
|
package/dist/runtime/index.js
CHANGED
|
@@ -224,6 +224,20 @@ var init_severity = __esm({
|
|
|
224
224
|
}
|
|
225
225
|
});
|
|
226
226
|
|
|
227
|
+
// src/constants/telemetry.ts
|
|
228
|
+
var POSTHOG_HOST, POSTHOG_CAPTURE_PATH, POSTHOG_REQUEST_TIMEOUT_MS, POSTHOG_SPAWN_TIMEOUT_MS, SIGNAL_EXIT_SIGINT, SIGNAL_EXIT_SIGTERM;
|
|
229
|
+
var init_telemetry = __esm({
|
|
230
|
+
"src/constants/telemetry.ts"() {
|
|
231
|
+
"use strict";
|
|
232
|
+
POSTHOG_HOST = "https://us.i.posthog.com";
|
|
233
|
+
POSTHOG_CAPTURE_PATH = "/i/v0/e/";
|
|
234
|
+
POSTHOG_REQUEST_TIMEOUT_MS = 3e3;
|
|
235
|
+
POSTHOG_SPAWN_TIMEOUT_MS = 5e3;
|
|
236
|
+
SIGNAL_EXIT_SIGINT = 130;
|
|
237
|
+
SIGNAL_EXIT_SIGTERM = 143;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
227
241
|
// src/constants/index.ts
|
|
228
242
|
var init_constants = __esm({
|
|
229
243
|
"src/constants/index.ts"() {
|
|
@@ -238,6 +252,7 @@ var init_constants = __esm({
|
|
|
238
252
|
init_mcp();
|
|
239
253
|
init_encoding();
|
|
240
254
|
init_severity();
|
|
255
|
+
init_telemetry();
|
|
241
256
|
}
|
|
242
257
|
});
|
|
243
258
|
|
|
@@ -2526,11 +2541,33 @@ var init_finding_store = __esm({
|
|
|
2526
2541
|
|
|
2527
2542
|
// src/detect/project.ts
|
|
2528
2543
|
import { readFile as readFile2 } from "fs/promises";
|
|
2544
|
+
import { existsSync as existsSync4 } from "fs";
|
|
2529
2545
|
import { join } from "path";
|
|
2546
|
+
function detectFrameworkFromDeps(allDeps) {
|
|
2547
|
+
for (const f of FRAMEWORKS) {
|
|
2548
|
+
if (allDeps[f.dep]) return f.name;
|
|
2549
|
+
}
|
|
2550
|
+
return "unknown";
|
|
2551
|
+
}
|
|
2552
|
+
function detectPackageManagerSync(rootDir) {
|
|
2553
|
+
if (existsSync4(join(rootDir, "bun.lockb")) || existsSync4(join(rootDir, "bun.lock"))) return "bun";
|
|
2554
|
+
if (existsSync4(join(rootDir, "pnpm-lock.yaml"))) return "pnpm";
|
|
2555
|
+
if (existsSync4(join(rootDir, "yarn.lock"))) return "yarn";
|
|
2556
|
+
if (existsSync4(join(rootDir, "package-lock.json"))) return "npm";
|
|
2557
|
+
return "unknown";
|
|
2558
|
+
}
|
|
2559
|
+
var FRAMEWORKS;
|
|
2530
2560
|
var init_project = __esm({
|
|
2531
2561
|
"src/detect/project.ts"() {
|
|
2532
2562
|
"use strict";
|
|
2533
2563
|
init_fs();
|
|
2564
|
+
FRAMEWORKS = [
|
|
2565
|
+
{ name: "nextjs", dep: "next", devCmd: "next dev", bin: "next", defaultPort: 3e3, devArgs: ["dev", "--port"] },
|
|
2566
|
+
{ name: "remix", dep: "@remix-run/dev", devCmd: "remix dev", bin: "remix", defaultPort: 3e3, devArgs: ["dev"] },
|
|
2567
|
+
{ name: "nuxt", dep: "nuxt", devCmd: "nuxt dev", bin: "nuxt", defaultPort: 3e3, devArgs: ["dev", "--port"] },
|
|
2568
|
+
{ name: "vite", dep: "vite", devCmd: "vite", bin: "vite", defaultPort: 5173, devArgs: ["--port"] },
|
|
2569
|
+
{ name: "astro", dep: "astro", devCmd: "astro dev", bin: "astro", defaultPort: 4321, devArgs: ["dev", "--port"] }
|
|
2570
|
+
];
|
|
2534
2571
|
}
|
|
2535
2572
|
});
|
|
2536
2573
|
|
|
@@ -4147,7 +4184,7 @@ var init_src = __esm({
|
|
|
4147
4184
|
init_engine();
|
|
4148
4185
|
init_insights3();
|
|
4149
4186
|
init_insights2();
|
|
4150
|
-
VERSION = "0.8.
|
|
4187
|
+
VERSION = "0.8.4";
|
|
4151
4188
|
}
|
|
4152
4189
|
});
|
|
4153
4190
|
|
|
@@ -6646,16 +6683,35 @@ var init_page = __esm({
|
|
|
6646
6683
|
// src/telemetry/config.ts
|
|
6647
6684
|
import { homedir } from "os";
|
|
6648
6685
|
import { join as join2 } from "path";
|
|
6649
|
-
import { existsSync as
|
|
6686
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
6650
6687
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
6651
6688
|
function readConfig() {
|
|
6652
6689
|
try {
|
|
6653
|
-
if (!
|
|
6690
|
+
if (!existsSync5(CONFIG_PATH)) return null;
|
|
6654
6691
|
return JSON.parse(readFileSync3(CONFIG_PATH, "utf-8"));
|
|
6655
6692
|
} catch {
|
|
6656
6693
|
return null;
|
|
6657
6694
|
}
|
|
6658
6695
|
}
|
|
6696
|
+
function writeConfig(config) {
|
|
6697
|
+
try {
|
|
6698
|
+
if (!existsSync5(CONFIG_DIR))
|
|
6699
|
+
mkdirSync3(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
6700
|
+
writeFileSync3(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", {
|
|
6701
|
+
mode: 384
|
|
6702
|
+
});
|
|
6703
|
+
} catch {
|
|
6704
|
+
}
|
|
6705
|
+
}
|
|
6706
|
+
function getOrCreateConfig() {
|
|
6707
|
+
const existing = readConfig();
|
|
6708
|
+
if (existing && typeof existing.telemetry === "boolean" && existing.anonymousId) {
|
|
6709
|
+
return existing;
|
|
6710
|
+
}
|
|
6711
|
+
const config = { telemetry: true, anonymousId: randomUUID3() };
|
|
6712
|
+
writeConfig(config);
|
|
6713
|
+
return config;
|
|
6714
|
+
}
|
|
6659
6715
|
function isTelemetryEnabled() {
|
|
6660
6716
|
const env = process.env.BRAKIT_TELEMETRY;
|
|
6661
6717
|
if (env !== void 0) return env !== "false" && env !== "0" && env !== "off";
|
|
@@ -6672,21 +6728,126 @@ var init_config = __esm({
|
|
|
6672
6728
|
|
|
6673
6729
|
// src/telemetry/index.ts
|
|
6674
6730
|
import { platform, release, arch } from "os";
|
|
6731
|
+
import { spawnSync } from "child_process";
|
|
6732
|
+
function initSession(framework, packageManager, isCustomCommand, adapters) {
|
|
6733
|
+
session.startTime = Date.now();
|
|
6734
|
+
session.framework = framework;
|
|
6735
|
+
session.packageManager = packageManager;
|
|
6736
|
+
session.isCustomCommand = isCustomCommand;
|
|
6737
|
+
session.adapters = adapters;
|
|
6738
|
+
}
|
|
6739
|
+
function recordRequestCount(count) {
|
|
6740
|
+
session.requestCount = count;
|
|
6741
|
+
}
|
|
6742
|
+
function recordInsightTypes(types) {
|
|
6743
|
+
for (const t of types) session.insightTypes.add(t);
|
|
6744
|
+
}
|
|
6745
|
+
function recordRulesTriggered(rules) {
|
|
6746
|
+
for (const r of rules) session.rulesTriggered.add(r);
|
|
6747
|
+
}
|
|
6675
6748
|
function recordTabViewed(tab) {
|
|
6676
|
-
tabsViewed.add(tab);
|
|
6749
|
+
session.tabsViewed.add(tab);
|
|
6677
6750
|
}
|
|
6678
6751
|
function recordDashboardOpened() {
|
|
6679
|
-
dashboardOpened = true;
|
|
6752
|
+
session.dashboardOpened = true;
|
|
6753
|
+
}
|
|
6754
|
+
function speedBucket(ms) {
|
|
6755
|
+
if (ms === 0) return "none";
|
|
6756
|
+
if (ms < 200) return "<200ms";
|
|
6757
|
+
if (ms < 500) return "200-500ms";
|
|
6758
|
+
if (ms < 1e3) return "500-1000ms";
|
|
6759
|
+
if (ms < 2e3) return "1000-2000ms";
|
|
6760
|
+
if (ms < 5e3) return "2000-5000ms";
|
|
6761
|
+
return ">5000ms";
|
|
6762
|
+
}
|
|
6763
|
+
function trackSession(registry) {
|
|
6764
|
+
if (!isTelemetryEnabled()) return;
|
|
6765
|
+
const isFirstSession = readConfig() === null;
|
|
6766
|
+
const config = getOrCreateConfig();
|
|
6767
|
+
const metricsStore = registry.get("metrics-store");
|
|
6768
|
+
const analysisEngine = registry.get("analysis-engine");
|
|
6769
|
+
const live = metricsStore.getLiveEndpoints();
|
|
6770
|
+
const insights = analysisEngine.getInsights();
|
|
6771
|
+
const findings = analysisEngine.getFindings();
|
|
6772
|
+
let totalRequests = 0;
|
|
6773
|
+
let totalDuration = 0;
|
|
6774
|
+
let slowestP95 = 0;
|
|
6775
|
+
for (const ep of live) {
|
|
6776
|
+
totalRequests += ep.summary.totalRequests;
|
|
6777
|
+
totalDuration += ep.summary.p95Ms * ep.summary.totalRequests;
|
|
6778
|
+
if (ep.summary.p95Ms > slowestP95) slowestP95 = ep.summary.p95Ms;
|
|
6779
|
+
}
|
|
6780
|
+
const payload = {
|
|
6781
|
+
api_key: POSTHOG_KEY,
|
|
6782
|
+
event: "session",
|
|
6783
|
+
distinct_id: config.anonymousId,
|
|
6784
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6785
|
+
properties: {
|
|
6786
|
+
brakit_version: VERSION,
|
|
6787
|
+
node_version: process.version,
|
|
6788
|
+
os: `${platform()}-${release()}`,
|
|
6789
|
+
arch: arch(),
|
|
6790
|
+
framework: session.framework,
|
|
6791
|
+
package_manager: session.packageManager,
|
|
6792
|
+
is_custom_command: session.isCustomCommand,
|
|
6793
|
+
first_session: isFirstSession,
|
|
6794
|
+
adapters_detected: session.adapters,
|
|
6795
|
+
request_count: session.requestCount,
|
|
6796
|
+
error_count: registry.get("error-store").getAll().length,
|
|
6797
|
+
query_count: registry.get("query-store").getAll().length,
|
|
6798
|
+
fetch_count: registry.get("fetch-store").getAll().length,
|
|
6799
|
+
insight_count: insights.length,
|
|
6800
|
+
finding_count: findings.length,
|
|
6801
|
+
insight_types: [...session.insightTypes],
|
|
6802
|
+
rules_triggered: [...session.rulesTriggered],
|
|
6803
|
+
endpoint_count: live.length,
|
|
6804
|
+
avg_duration_ms: totalRequests > 0 ? Math.round(totalDuration / totalRequests) : 0,
|
|
6805
|
+
slowest_endpoint_bucket: speedBucket(slowestP95),
|
|
6806
|
+
tabs_viewed: [...session.tabsViewed],
|
|
6807
|
+
dashboard_opened: session.dashboardOpened,
|
|
6808
|
+
explain_used: session.explainUsed,
|
|
6809
|
+
session_duration_s: Math.round((Date.now() - session.startTime) / 1e3),
|
|
6810
|
+
$lib: "brakit",
|
|
6811
|
+
$process_person_profile: false,
|
|
6812
|
+
$geoip_disable: true
|
|
6813
|
+
}
|
|
6814
|
+
};
|
|
6815
|
+
try {
|
|
6816
|
+
const body = JSON.stringify(payload);
|
|
6817
|
+
const url = `${POSTHOG_HOST}${POSTHOG_CAPTURE_PATH}`;
|
|
6818
|
+
spawnSync(
|
|
6819
|
+
process.execPath,
|
|
6820
|
+
[
|
|
6821
|
+
"-e",
|
|
6822
|
+
`fetch(${JSON.stringify(url)},{method:"POST",headers:{"content-type":"application/json"},body:${JSON.stringify(body)},signal:AbortSignal.timeout(${POSTHOG_REQUEST_TIMEOUT_MS})}).catch(()=>{})`
|
|
6823
|
+
],
|
|
6824
|
+
{ timeout: POSTHOG_SPAWN_TIMEOUT_MS, stdio: "ignore" }
|
|
6825
|
+
);
|
|
6826
|
+
} catch {
|
|
6827
|
+
}
|
|
6680
6828
|
}
|
|
6681
|
-
var
|
|
6682
|
-
var
|
|
6829
|
+
var POSTHOG_KEY, session;
|
|
6830
|
+
var init_telemetry2 = __esm({
|
|
6683
6831
|
"src/telemetry/index.ts"() {
|
|
6684
6832
|
"use strict";
|
|
6685
6833
|
init_src();
|
|
6686
6834
|
init_config();
|
|
6835
|
+
init_telemetry();
|
|
6687
6836
|
init_config();
|
|
6688
|
-
|
|
6689
|
-
|
|
6837
|
+
POSTHOG_KEY = "phc_E9TwydCGnSfPLIUhNxChpeg32TSowjk31KiPhnLPP0x";
|
|
6838
|
+
session = {
|
|
6839
|
+
startTime: 0,
|
|
6840
|
+
framework: "",
|
|
6841
|
+
packageManager: "",
|
|
6842
|
+
isCustomCommand: false,
|
|
6843
|
+
adapters: [],
|
|
6844
|
+
requestCount: 0,
|
|
6845
|
+
insightTypes: /* @__PURE__ */ new Set(),
|
|
6846
|
+
rulesTriggered: /* @__PURE__ */ new Set(),
|
|
6847
|
+
tabsViewed: /* @__PURE__ */ new Set(),
|
|
6848
|
+
dashboardOpened: false,
|
|
6849
|
+
explainUsed: false
|
|
6850
|
+
};
|
|
6690
6851
|
}
|
|
6691
6852
|
});
|
|
6692
6853
|
|
|
@@ -6753,7 +6914,7 @@ var init_router = __esm({
|
|
|
6753
6914
|
init_findings();
|
|
6754
6915
|
init_sse();
|
|
6755
6916
|
init_page();
|
|
6756
|
-
|
|
6917
|
+
init_telemetry2();
|
|
6757
6918
|
SECURITY_HEADERS = {
|
|
6758
6919
|
"x-content-type-options": "nosniff",
|
|
6759
6920
|
"x-frame-options": "DENY",
|
|
@@ -7155,7 +7316,7 @@ var init_metrics_store = __esm({
|
|
|
7155
7316
|
for (const [endpoint, acc] of this.accumulators) {
|
|
7156
7317
|
if (acc.durations.length === 0) continue;
|
|
7157
7318
|
const n = acc.totalRequestCount;
|
|
7158
|
-
const
|
|
7319
|
+
const session2 = {
|
|
7159
7320
|
sessionId: this.sessionId,
|
|
7160
7321
|
startedAt: this.sessionStart,
|
|
7161
7322
|
avgDurationMs: Math.round(acc.totalDurationSum / n),
|
|
@@ -7171,9 +7332,9 @@ var init_metrics_store = __esm({
|
|
|
7171
7332
|
(s) => s.sessionId === this.sessionId
|
|
7172
7333
|
);
|
|
7173
7334
|
if (existingIdx !== -1) {
|
|
7174
|
-
epMetrics.sessions[existingIdx] =
|
|
7335
|
+
epMetrics.sessions[existingIdx] = session2;
|
|
7175
7336
|
} else {
|
|
7176
|
-
epMetrics.sessions.push(
|
|
7337
|
+
epMetrics.sessions.push(session2);
|
|
7177
7338
|
}
|
|
7178
7339
|
if (epMetrics.sessions.length > METRICS_MAX_SESSIONS) {
|
|
7179
7340
|
epMetrics.sessions = epMetrics.sessions.slice(-METRICS_MAX_SESSIONS);
|
|
@@ -7209,7 +7370,7 @@ var init_metrics_store = __esm({
|
|
|
7209
7370
|
});
|
|
7210
7371
|
|
|
7211
7372
|
// src/store/metrics/persistence.ts
|
|
7212
|
-
import { readFileSync as readFileSync4, existsSync as
|
|
7373
|
+
import { readFileSync as readFileSync4, existsSync as existsSync6, unlinkSync } from "fs";
|
|
7213
7374
|
import { resolve as resolve3 } from "path";
|
|
7214
7375
|
var FileMetricsPersistence;
|
|
7215
7376
|
var init_persistence = __esm({
|
|
@@ -7232,7 +7393,7 @@ var init_persistence = __esm({
|
|
|
7232
7393
|
}
|
|
7233
7394
|
load() {
|
|
7234
7395
|
try {
|
|
7235
|
-
if (
|
|
7396
|
+
if (existsSync6(this.metricsPath)) {
|
|
7236
7397
|
const raw = readFileSync4(this.metricsPath, "utf-8");
|
|
7237
7398
|
const parsed = JSON.parse(raw);
|
|
7238
7399
|
if (parsed?.version === 1 && Array.isArray(parsed.endpoints)) {
|
|
@@ -7252,7 +7413,7 @@ var init_persistence = __esm({
|
|
|
7252
7413
|
}
|
|
7253
7414
|
remove() {
|
|
7254
7415
|
try {
|
|
7255
|
-
if (
|
|
7416
|
+
if (existsSync6(this.metricsPath)) {
|
|
7256
7417
|
unlinkSync(this.metricsPath);
|
|
7257
7418
|
}
|
|
7258
7419
|
} catch {
|
|
@@ -7602,7 +7763,7 @@ var setup_exports = {};
|
|
|
7602
7763
|
__export(setup_exports, {
|
|
7603
7764
|
setup: () => setup
|
|
7604
7765
|
});
|
|
7605
|
-
import { writeFileSync as writeFileSync4, readFileSync as readFileSync5, mkdirSync as mkdirSync4, existsSync as
|
|
7766
|
+
import { writeFileSync as writeFileSync4, readFileSync as readFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, unlinkSync as unlinkSync2 } from "fs";
|
|
7606
7767
|
import { resolve as resolve4 } from "path";
|
|
7607
7768
|
function setup() {
|
|
7608
7769
|
if (initialized) return;
|
|
@@ -7635,6 +7796,19 @@ function setup() {
|
|
|
7635
7796
|
const adapterRegistry = createDefaultRegistry();
|
|
7636
7797
|
adapterRegistry.patchAll(telemetryEmit);
|
|
7637
7798
|
const cwd = process.cwd();
|
|
7799
|
+
let framework = "unknown";
|
|
7800
|
+
try {
|
|
7801
|
+
const pkg = JSON.parse(readFileSync5(resolve4(cwd, "package.json"), "utf-8"));
|
|
7802
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
7803
|
+
framework = detectFrameworkFromDeps(allDeps);
|
|
7804
|
+
} catch {
|
|
7805
|
+
}
|
|
7806
|
+
initSession(
|
|
7807
|
+
framework,
|
|
7808
|
+
detectPackageManagerSync(cwd),
|
|
7809
|
+
false,
|
|
7810
|
+
adapterRegistry.getActive().map((a) => a.name)
|
|
7811
|
+
);
|
|
7638
7812
|
const metricsStore = new MetricsStore(new FileMetricsPersistence(cwd));
|
|
7639
7813
|
metricsStore.start();
|
|
7640
7814
|
registry.register("metrics-store", metricsStore);
|
|
@@ -7668,9 +7842,9 @@ function setup() {
|
|
|
7668
7842
|
onFirstRequest(port) {
|
|
7669
7843
|
setBrakitPort(port);
|
|
7670
7844
|
const dir = resolve4(cwd, METRICS_DIR);
|
|
7671
|
-
if (!
|
|
7845
|
+
if (!existsSync7(dir)) mkdirSync4(dir, { recursive: true });
|
|
7672
7846
|
const portPath = resolve4(cwd, PORT_FILE);
|
|
7673
|
-
if (
|
|
7847
|
+
if (existsSync7(portPath)) {
|
|
7674
7848
|
const old = readFileSync5(portPath, "utf-8").trim();
|
|
7675
7849
|
if (old && old !== String(port)) {
|
|
7676
7850
|
brakitDebug(`Overwriting stale port file (was ${old}, now ${port})`);
|
|
@@ -7682,7 +7856,14 @@ function setup() {
|
|
|
7682
7856
|
`);
|
|
7683
7857
|
}
|
|
7684
7858
|
});
|
|
7685
|
-
|
|
7859
|
+
let teardownCalled = false;
|
|
7860
|
+
const runTeardown = () => {
|
|
7861
|
+
if (teardownCalled) return;
|
|
7862
|
+
teardownCalled = true;
|
|
7863
|
+
recordRequestCount(requestStore.getAll().length);
|
|
7864
|
+
recordInsightTypes(analysisEngine.getInsights().map((i) => i.type));
|
|
7865
|
+
recordRulesTriggered(analysisEngine.getFindings().map((f) => f.rule));
|
|
7866
|
+
trackSession(registry);
|
|
7686
7867
|
uninstallInterceptor();
|
|
7687
7868
|
terminalDispose?.();
|
|
7688
7869
|
analysisEngine.stop();
|
|
@@ -7690,9 +7871,18 @@ function setup() {
|
|
|
7690
7871
|
metricsStore.stop();
|
|
7691
7872
|
try {
|
|
7692
7873
|
const portPath = resolve4(cwd, PORT_FILE);
|
|
7693
|
-
if (
|
|
7874
|
+
if (existsSync7(portPath)) unlinkSync2(portPath);
|
|
7694
7875
|
} catch {
|
|
7695
7876
|
}
|
|
7877
|
+
};
|
|
7878
|
+
health.setTeardown(runTeardown);
|
|
7879
|
+
process.once("SIGINT", () => {
|
|
7880
|
+
runTeardown();
|
|
7881
|
+
process.exit(SIGNAL_EXIT_SIGINT);
|
|
7882
|
+
});
|
|
7883
|
+
process.once("SIGTERM", () => {
|
|
7884
|
+
runTeardown();
|
|
7885
|
+
process.exit(SIGNAL_EXIT_SIGTERM);
|
|
7696
7886
|
});
|
|
7697
7887
|
}
|
|
7698
7888
|
var initialized;
|
|
@@ -7717,9 +7907,12 @@ var init_setup = __esm({
|
|
|
7717
7907
|
init_terminal();
|
|
7718
7908
|
init_src();
|
|
7719
7909
|
init_constants();
|
|
7910
|
+
init_telemetry();
|
|
7720
7911
|
init_health2();
|
|
7721
7912
|
init_interceptor();
|
|
7722
7913
|
init_log();
|
|
7914
|
+
init_project();
|
|
7915
|
+
init_telemetry2();
|
|
7723
7916
|
initialized = false;
|
|
7724
7917
|
}
|
|
7725
7918
|
});
|
package/package.json
CHANGED