brakit 0.8.1 → 0.8.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 +5 -5
- package/dist/api.d.ts +103 -44
- package/dist/api.js +153 -266
- package/dist/bin/brakit.js +122 -209
- package/dist/mcp/server.js +57 -13
- package/dist/runtime/index.js +1623 -1539
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<h1 align="center"><img src="docs/images/icon.png" height="24" alt="" /> Brakit</h1>
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<b>
|
|
5
|
-
Every request, query, and security issue
|
|
6
|
-
<b>Open source · Local first · Zero config ·
|
|
4
|
+
<b>AI writes your code. Brakit watches what it does.</b> <br />
|
|
5
|
+
Every request, query, and security issue, caught before you ship. <br />
|
|
6
|
+
<b>Open source · Local first · Zero config · AI-native via MCP</b>
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<h3 align="center">
|
|
@@ -74,7 +74,7 @@ Dashboard at `http://localhost:<port>/__brakit`. Insights in the terminal.
|
|
|
74
74
|
- **Full server tracing** — fetch calls, DB queries, console logs, errors — zero code changes
|
|
75
75
|
- **Response overfetch** — large JSON responses with many fields your client doesn't use
|
|
76
76
|
- **Performance tracking** — health grades and p95 trends across dev sessions
|
|
77
|
-
- **AI-native via MCP** — Claude
|
|
77
|
+
- **AI-native via MCP** — Claude Code and Cursor can query findings, inspect endpoints, and verify fixes directly
|
|
78
78
|
|
|
79
79
|
---
|
|
80
80
|
|
|
@@ -188,7 +188,7 @@ npm run typecheck # Type-check without emitting
|
|
|
188
188
|
npm test # Run tests with vitest
|
|
189
189
|
```
|
|
190
190
|
|
|
191
|
-
|
|
191
|
+
Minimal production dependencies. Everything else is Node.js built-ins.
|
|
192
192
|
|
|
193
193
|
### Architecture
|
|
194
194
|
|
package/dist/api.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { IncomingHttpHeaders } from 'node:http';
|
|
2
|
+
|
|
1
3
|
type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | (string & {});
|
|
2
4
|
type FlatHeaders = Record<string, string>;
|
|
3
5
|
interface TracedRequest {
|
|
@@ -117,10 +119,6 @@ interface EndpointMetrics {
|
|
|
117
119
|
sessions: SessionMetric[];
|
|
118
120
|
dataPoints?: LiveRequestPoint[];
|
|
119
121
|
}
|
|
120
|
-
interface MetricsData {
|
|
121
|
-
version: 1;
|
|
122
|
-
endpoints: EndpointMetrics[];
|
|
123
|
-
}
|
|
124
122
|
interface LiveRequestPoint {
|
|
125
123
|
timestamp: number;
|
|
126
124
|
durationMs: number;
|
|
@@ -239,15 +237,22 @@ declare class FindingStore {
|
|
|
239
237
|
private findings;
|
|
240
238
|
private flushTimer;
|
|
241
239
|
private dirty;
|
|
242
|
-
private
|
|
240
|
+
private readonly writer;
|
|
243
241
|
private readonly findingsPath;
|
|
244
|
-
private readonly tmpPath;
|
|
245
|
-
private readonly metricsDir;
|
|
246
242
|
constructor(rootDir: string);
|
|
247
243
|
start(): void;
|
|
248
244
|
stop(): void;
|
|
249
245
|
upsert(finding: SecurityFinding, source: FindingSource): StatefulFinding;
|
|
250
246
|
transition(findingId: string, state: FindingState): boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Reconcile passive findings against the current analysis results.
|
|
249
|
+
*
|
|
250
|
+
* Passive findings are detected by continuous scanning (not user-triggered).
|
|
251
|
+
* When a previously-seen finding is absent from the current results, it means
|
|
252
|
+
* the issue has been fixed — transition it to "resolved" automatically.
|
|
253
|
+
* Active findings (from MCP verify-fix) are not auto-resolved because they
|
|
254
|
+
* require explicit verification.
|
|
255
|
+
*/
|
|
251
256
|
reconcilePassive(currentFindings: readonly SecurityFinding[]): void;
|
|
252
257
|
getAll(): readonly StatefulFinding[];
|
|
253
258
|
getByState(state: FindingState): readonly StatefulFinding[];
|
|
@@ -256,8 +261,7 @@ declare class FindingStore {
|
|
|
256
261
|
private load;
|
|
257
262
|
private flush;
|
|
258
263
|
private flushSync;
|
|
259
|
-
private
|
|
260
|
-
private ensureDir;
|
|
264
|
+
private serialize;
|
|
261
265
|
}
|
|
262
266
|
|
|
263
267
|
interface BrakitAdapter {
|
|
@@ -312,44 +316,105 @@ declare class AdapterRegistry {
|
|
|
312
316
|
getActive(): readonly BrakitAdapter[];
|
|
313
317
|
}
|
|
314
318
|
|
|
315
|
-
interface
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
319
|
+
interface AnalysisUpdate {
|
|
320
|
+
insights: Insight[];
|
|
321
|
+
findings: SecurityFinding[];
|
|
322
|
+
statefulFindings: readonly StatefulFinding[];
|
|
323
|
+
statefulInsights: readonly StatefulInsight[];
|
|
324
|
+
}
|
|
325
|
+
interface ChannelMap {
|
|
326
|
+
"telemetry:fetch": Omit<TracedFetch, "id">;
|
|
327
|
+
"telemetry:query": Omit<TracedQuery, "id">;
|
|
328
|
+
"telemetry:log": Omit<TracedLog, "id">;
|
|
329
|
+
"telemetry:error": Omit<TracedError, "id">;
|
|
330
|
+
"request:completed": TracedRequest;
|
|
331
|
+
"analysis:updated": AnalysisUpdate;
|
|
332
|
+
"store:cleared": void;
|
|
333
|
+
}
|
|
334
|
+
type Listener<T> = (data: T) => void;
|
|
335
|
+
declare class EventBus {
|
|
336
|
+
private listeners;
|
|
337
|
+
emit<K extends keyof ChannelMap>(channel: K, data: ChannelMap[K]): void;
|
|
338
|
+
on<K extends keyof ChannelMap>(channel: K, fn: Listener<ChannelMap[K]>): () => void;
|
|
339
|
+
off<K extends keyof ChannelMap>(channel: K, fn: Listener<ChannelMap[K]>): void;
|
|
320
340
|
}
|
|
321
341
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
342
|
+
interface CaptureInput {
|
|
343
|
+
requestId: string;
|
|
344
|
+
method: string;
|
|
345
|
+
url: string;
|
|
346
|
+
requestHeaders: IncomingHttpHeaders;
|
|
347
|
+
requestBody: Buffer | null;
|
|
348
|
+
statusCode: number;
|
|
349
|
+
responseHeaders: IncomingHttpHeaders;
|
|
350
|
+
responseBody: Buffer | null;
|
|
351
|
+
responseContentType: string;
|
|
352
|
+
startTime: number;
|
|
353
|
+
endTime?: number;
|
|
354
|
+
config: Pick<BrakitConfig, "maxBodyCapture">;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
interface TelemetryStoreInterface<T extends TelemetryEntry> {
|
|
358
|
+
add(data: Omit<T, "id">): T;
|
|
359
|
+
getAll(): readonly T[];
|
|
360
|
+
getByRequest(requestId: string): T[];
|
|
361
|
+
clear(): void;
|
|
362
|
+
}
|
|
363
|
+
interface RequestStoreInterface {
|
|
364
|
+
capture(input: CaptureInput): TracedRequest;
|
|
365
|
+
getAll(): readonly TracedRequest[];
|
|
366
|
+
clear(): void;
|
|
367
|
+
}
|
|
368
|
+
interface MetricsStoreInterface {
|
|
334
369
|
recordRequest(req: TracedRequest, metrics: RequestMetrics): void;
|
|
335
370
|
getAll(): readonly EndpointMetrics[];
|
|
336
371
|
getEndpoint(endpoint: string): EndpointMetrics | undefined;
|
|
337
372
|
getLiveEndpoints(): LiveEndpointData[];
|
|
338
373
|
reset(): void;
|
|
339
|
-
|
|
340
|
-
|
|
374
|
+
start(): void;
|
|
375
|
+
stop(): void;
|
|
376
|
+
}
|
|
377
|
+
interface FindingStoreInterface {
|
|
378
|
+
upsert(finding: SecurityFinding, source: FindingSource): StatefulFinding;
|
|
379
|
+
transition(findingId: string, state: FindingState): boolean;
|
|
380
|
+
reconcilePassive(findings: readonly SecurityFinding[]): void;
|
|
381
|
+
getAll(): readonly StatefulFinding[];
|
|
382
|
+
getByState(state: FindingState): readonly StatefulFinding[];
|
|
383
|
+
get(findingId: string): StatefulFinding | undefined;
|
|
384
|
+
clear(): void;
|
|
385
|
+
start(): void;
|
|
386
|
+
stop(): void;
|
|
387
|
+
}
|
|
388
|
+
interface AnalysisEngineInterface {
|
|
389
|
+
start(): void;
|
|
390
|
+
stop(): void;
|
|
391
|
+
recompute(): void;
|
|
392
|
+
getInsights(): readonly Insight[];
|
|
393
|
+
getFindings(): readonly SecurityFinding[];
|
|
394
|
+
getStatefulInsights(): readonly StatefulInsight[];
|
|
395
|
+
getStatefulFindings(): readonly StatefulFinding[];
|
|
341
396
|
}
|
|
342
397
|
|
|
343
|
-
interface
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
398
|
+
interface ServiceMap {
|
|
399
|
+
"event-bus": EventBus;
|
|
400
|
+
"request-store": RequestStoreInterface;
|
|
401
|
+
"query-store": TelemetryStoreInterface<TracedQuery>;
|
|
402
|
+
"fetch-store": TelemetryStoreInterface<TracedFetch>;
|
|
403
|
+
"log-store": TelemetryStoreInterface<TracedLog>;
|
|
404
|
+
"error-store": TelemetryStoreInterface<TracedError>;
|
|
405
|
+
"metrics-store": MetricsStoreInterface;
|
|
406
|
+
"finding-store": FindingStoreInterface;
|
|
407
|
+
"analysis-engine": AnalysisEngineInterface;
|
|
408
|
+
}
|
|
409
|
+
declare class ServiceRegistry {
|
|
410
|
+
private services;
|
|
411
|
+
register<K extends keyof ServiceMap>(name: K, service: ServiceMap[K]): void;
|
|
412
|
+
get<K extends keyof ServiceMap>(name: K): ServiceMap[K];
|
|
413
|
+
has<K extends keyof ServiceMap>(name: K): boolean;
|
|
348
414
|
}
|
|
349
|
-
|
|
415
|
+
|
|
350
416
|
declare class AnalysisEngine {
|
|
351
|
-
private
|
|
352
|
-
private findingStore?;
|
|
417
|
+
private registry;
|
|
353
418
|
private debounceMs;
|
|
354
419
|
private scanner;
|
|
355
420
|
private insightTracker;
|
|
@@ -357,16 +422,10 @@ declare class AnalysisEngine {
|
|
|
357
422
|
private cachedFindings;
|
|
358
423
|
private cachedStatefulInsights;
|
|
359
424
|
private debounceTimer;
|
|
360
|
-
private
|
|
361
|
-
|
|
362
|
-
private boundQueryListener;
|
|
363
|
-
private boundErrorListener;
|
|
364
|
-
private boundLogListener;
|
|
365
|
-
constructor(metricsStore: MetricsStore, findingStore?: FindingStore | undefined, debounceMs?: number);
|
|
425
|
+
private subs;
|
|
426
|
+
constructor(registry: ServiceRegistry, debounceMs?: number);
|
|
366
427
|
start(): void;
|
|
367
428
|
stop(): void;
|
|
368
|
-
onUpdate(fn: AnalysisListener): void;
|
|
369
|
-
offUpdate(fn: AnalysisListener): void;
|
|
370
429
|
getInsights(): readonly Insight[];
|
|
371
430
|
getFindings(): readonly SecurityFinding[];
|
|
372
431
|
getStatefulFindings(): readonly StatefulFinding[];
|