brakit 0.7.0 → 0.7.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 +38 -46
- package/dist/api.js +1 -1
- package/dist/bin/brakit.js +1 -1
- package/dist/runtime/index.js +36 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**See what your app is actually doing.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Every request, query, and security issue — before you ship.
|
|
6
6
|
|
|
7
7
|
Open source · Local only · Zero config · 2 dependencies
|
|
8
8
|
|
|
@@ -10,25 +10,22 @@ Open source · Local only · Zero config · 2 dependencies
|
|
|
10
10
|
[](https://nodejs.org)
|
|
11
11
|
[](https://typescriptlang.org)
|
|
12
12
|
|
|
13
|
-
<!-- TODO: Add demo gif showing: npx brakit dev → use app → dashboard shows issues -->
|
|
14
|
-
<!--  -->
|
|
15
|
-
|
|
16
13
|
---
|
|
17
14
|
|
|
18
15
|
## Quick Start
|
|
19
16
|
|
|
20
17
|
```bash
|
|
21
|
-
npx brakit
|
|
18
|
+
npx brakit install
|
|
22
19
|
```
|
|
23
20
|
|
|
24
|
-
That's it. Brakit
|
|
21
|
+
That's it. Brakit detects your framework, adds itself as a devDependency, and creates the instrumentation file. Start your app normally:
|
|
25
22
|
|
|
26
23
|
```bash
|
|
27
|
-
|
|
28
|
-
npx brakit dev --show-static # Include static assets in output
|
|
29
|
-
npx brakit dev ./my-app # Specify project directory
|
|
24
|
+
npm run dev
|
|
30
25
|
```
|
|
31
26
|
|
|
27
|
+
Dashboard at `http://localhost:<port>/__brakit`. Insights in the terminal.
|
|
28
|
+
|
|
32
29
|
> **Requirements:** Node.js >= 18 and a project with `package.json`.
|
|
33
30
|
|
|
34
31
|
[Documentation](https://brakit.ai/docs) · [Website](https://brakit.ai)
|
|
@@ -78,32 +75,33 @@ Developers using AI tools (Cursor, Copilot, Claude Code) to generate API code th
|
|
|
78
75
|
|
|
79
76
|
---
|
|
80
77
|
|
|
81
|
-
## Principles — ZEAL
|
|
82
|
-
|
|
83
|
-
Everything we build is anchored around four pillars:
|
|
84
|
-
|
|
85
|
-
| | Pillar | What it means |
|
|
86
|
-
|---|---|---|
|
|
87
|
-
| **Z** | **Zero Config** | One command to start, zero config by default. Optional middleware for deeper integration — but the default path is always zero-touch. |
|
|
88
|
-
| **E** | **Extensible** | Open source. One file, one interface. Add a database adapter, security rule, or language SDK without touching brakit's core. |
|
|
89
|
-
| **A** | **AI-Native** | Built for the era where AI writes code humans don't fully review. A safety net for AI-generated APIs. |
|
|
90
|
-
| **L** | **Language Agnostic** | HTTP proxy works with any backend. SDK protocol accepts events from any language. Not locked to Node.js. |
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
78
|
## How It Works
|
|
95
79
|
|
|
96
80
|
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
81
|
+
import 'brakit' → hooks into http.Server → captures everything
|
|
82
|
+
|
|
|
83
|
+
+-- Dashboard UI (/__brakit)
|
|
84
|
+
+-- Live SSE stream (real-time updates)
|
|
85
|
+
+-- Terminal output (insights as you develop)
|
|
102
86
|
```
|
|
103
87
|
|
|
104
|
-
|
|
88
|
+
`import 'brakit'` runs inside your process. It patches `http.Server.prototype.emit` to intercept all requests — capturing request/response pairs, grouping them into actions, and streaming everything to the dashboard at `/__brakit` on your existing port. No proxy, no second process, no different port.
|
|
89
|
+
|
|
90
|
+
Instrumentation hooks capture fetch calls, DB queries, console output, and errors automatically — zero code changes.
|
|
105
91
|
|
|
106
|
-
|
|
92
|
+
### Production Safety
|
|
93
|
+
|
|
94
|
+
Brakit never runs in production. 7 independent layers ensure it:
|
|
95
|
+
|
|
96
|
+
| # | Layer | How it blocks |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| 1 | `shouldActivate()` | Checks `NODE_ENV` + 15 cloud/CI env vars |
|
|
99
|
+
| 2 | `instrumentation.ts` guard | Its own `NODE_ENV !== 'production'` check |
|
|
100
|
+
| 3 | devDependency | Pruned in production builds |
|
|
101
|
+
| 4 | `try/catch` on import | Missing module = silent no-op |
|
|
102
|
+
| 5 | Localhost-only dashboard | Non-local IPs get 404 on `/__brakit` |
|
|
103
|
+
| 6 | `safeWrap` + circuit breaker | 10 errors = brakit self-disables |
|
|
104
|
+
| 7 | `BRAKIT_DISABLE=true` | Manual kill switch |
|
|
107
105
|
|
|
108
106
|
### Supported Frameworks
|
|
109
107
|
|
|
@@ -114,7 +112,8 @@ The instrumentation layer runs inside your dev server process (injected via `--i
|
|
|
114
112
|
| Nuxt | Auto-detect |
|
|
115
113
|
| Vite | Auto-detect |
|
|
116
114
|
| Astro | Auto-detect |
|
|
117
|
-
|
|
|
115
|
+
| Express | Auto-detect |
|
|
116
|
+
| Fastify | Auto-detect |
|
|
118
117
|
|
|
119
118
|
### Supported Databases
|
|
120
119
|
|
|
@@ -129,16 +128,14 @@ The instrumentation layer runs inside your dev server process (injected via `--i
|
|
|
129
128
|
|
|
130
129
|
---
|
|
131
130
|
|
|
132
|
-
##
|
|
131
|
+
## Uninstall
|
|
133
132
|
|
|
134
133
|
```bash
|
|
135
|
-
npx brakit
|
|
136
|
-
npx brakit dev --port 3000 # Custom proxy port (default: 3000)
|
|
137
|
-
npx brakit dev --show-static # Show static asset requests
|
|
138
|
-
npx brakit dev ./my-app # Specify project directory
|
|
139
|
-
npx brakit dev --command "python manage.py" # Any backend, any language
|
|
134
|
+
npx brakit uninstall
|
|
140
135
|
```
|
|
141
136
|
|
|
137
|
+
Removes the instrumentation file and devDependency. Your app is unchanged.
|
|
138
|
+
|
|
142
139
|
---
|
|
143
140
|
|
|
144
141
|
## Development
|
|
@@ -158,25 +155,21 @@ Only 2 production dependencies: `citty` (CLI) and `picocolors` (terminal colors)
|
|
|
158
155
|
|
|
159
156
|
### Architecture
|
|
160
157
|
|
|
161
|
-
For a full walkthrough of how brakit works — the two-process model, adapter
|
|
162
|
-
system, analysis engine, and SDK protocol — see
|
|
163
|
-
[How Brakit Works](docs/design/architecture.md).
|
|
164
|
-
|
|
165
158
|
```
|
|
166
159
|
src/
|
|
160
|
+
runtime/ In-process entry point, server hooks, capture, safety
|
|
167
161
|
analysis/ Security scanning, N+1 detection, insights engine
|
|
168
162
|
rules/ SecurityRule implementations (one file per rule)
|
|
169
|
-
cli/ CLI
|
|
163
|
+
cli/ CLI commands (install, uninstall)
|
|
170
164
|
dashboard/
|
|
171
|
-
api/ REST handlers — requests, flows, telemetry, metrics
|
|
165
|
+
api/ REST handlers — requests, flows, telemetry, metrics
|
|
172
166
|
client/ Browser JS generated as template strings
|
|
173
167
|
views/ Tab renderers (overview, flows, graph, etc.)
|
|
174
168
|
styles/ CSS modules
|
|
175
169
|
detect/ Framework auto-detection
|
|
176
|
-
instrument/
|
|
170
|
+
instrument/ Runtime hooks and database adapters
|
|
177
171
|
adapters/ BrakitAdapter implementations (one file per library)
|
|
178
|
-
hooks/ Core
|
|
179
|
-
proxy/ HTTP reverse proxy, request capture, WebSocket forwarding
|
|
172
|
+
hooks/ Core hooks (fetch, console, errors, context)
|
|
180
173
|
store/ In-memory telemetry stores + persistent metrics
|
|
181
174
|
types/ TypeScript definitions by domain
|
|
182
175
|
```
|
|
@@ -193,7 +186,6 @@ Some areas where help would be great:
|
|
|
193
186
|
|
|
194
187
|
- **Database adapters** — Drizzle, Mongoose, SQLite, MongoDB
|
|
195
188
|
- **Security rules** — More patterns, configurable severity
|
|
196
|
-
- **Language SDKs** — Python, Go, Ruby (uses the [ingest protocol](docs/design/architecture.md#supporting-other-languages))
|
|
197
189
|
- **Dashboard** — Request diff, timeline view, HAR export
|
|
198
190
|
|
|
199
191
|
Please open an issue first for larger changes so we can discuss the approach.
|
package/dist/api.js
CHANGED
package/dist/bin/brakit.js
CHANGED
|
@@ -693,7 +693,7 @@ import { resolve as resolve2 } from "path";
|
|
|
693
693
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
694
694
|
|
|
695
695
|
// src/index.ts
|
|
696
|
-
var VERSION = "0.7.
|
|
696
|
+
var VERSION = "0.7.2";
|
|
697
697
|
|
|
698
698
|
// src/cli/commands/install.ts
|
|
699
699
|
var IMPORT_LINE = `import "brakit";`;
|
package/dist/runtime/index.js
CHANGED
|
@@ -3669,7 +3669,7 @@ var init_src = __esm({
|
|
|
3669
3669
|
init_rules();
|
|
3670
3670
|
init_engine();
|
|
3671
3671
|
init_insights2();
|
|
3672
|
-
VERSION = "0.7.
|
|
3672
|
+
VERSION = "0.7.2";
|
|
3673
3673
|
}
|
|
3674
3674
|
});
|
|
3675
3675
|
|
|
@@ -6296,48 +6296,48 @@ function outgoingToIncoming(headers) {
|
|
|
6296
6296
|
function captureInProcess(req, res, requestId) {
|
|
6297
6297
|
const startTime = performance.now();
|
|
6298
6298
|
const method = req.method ?? "GET";
|
|
6299
|
-
const shouldCaptureBody = method !== "GET" && method !== "HEAD";
|
|
6300
|
-
const reqChunks = [];
|
|
6301
|
-
let reqSize = 0;
|
|
6302
|
-
if (shouldCaptureBody) {
|
|
6303
|
-
req.on("data", (chunk) => {
|
|
6304
|
-
if (reqSize < DEFAULT_MAX_BODY_CAPTURE) {
|
|
6305
|
-
reqChunks.push(chunk);
|
|
6306
|
-
reqSize += chunk.length;
|
|
6307
|
-
}
|
|
6308
|
-
});
|
|
6309
|
-
}
|
|
6310
6299
|
const resChunks = [];
|
|
6311
6300
|
let resSize = 0;
|
|
6312
6301
|
const originalWrite = res.write;
|
|
6313
6302
|
const originalEnd = res.end;
|
|
6314
|
-
res.write = function(
|
|
6315
|
-
|
|
6316
|
-
const
|
|
6317
|
-
|
|
6318
|
-
|
|
6303
|
+
res.write = function(...args) {
|
|
6304
|
+
try {
|
|
6305
|
+
const chunk = args[0];
|
|
6306
|
+
if (chunk != null && typeof chunk !== "function" && resSize < DEFAULT_MAX_BODY_CAPTURE) {
|
|
6307
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
|
|
6308
|
+
resChunks.push(buf);
|
|
6309
|
+
resSize += buf.length;
|
|
6310
|
+
}
|
|
6311
|
+
} catch {
|
|
6319
6312
|
}
|
|
6320
|
-
return originalWrite.apply(this,
|
|
6313
|
+
return originalWrite.apply(this, args);
|
|
6321
6314
|
};
|
|
6322
|
-
res.end = function(
|
|
6323
|
-
|
|
6324
|
-
const
|
|
6325
|
-
|
|
6315
|
+
res.end = function(...args) {
|
|
6316
|
+
try {
|
|
6317
|
+
const chunk = typeof args[0] !== "function" ? args[0] : void 0;
|
|
6318
|
+
if (chunk != null && resSize < DEFAULT_MAX_BODY_CAPTURE) {
|
|
6319
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
|
|
6320
|
+
resChunks.push(buf);
|
|
6321
|
+
}
|
|
6322
|
+
} catch {
|
|
6323
|
+
}
|
|
6324
|
+
const result = originalEnd.apply(this, args);
|
|
6325
|
+
try {
|
|
6326
|
+
defaultStore.capture({
|
|
6327
|
+
requestId,
|
|
6328
|
+
method,
|
|
6329
|
+
url: req.url ?? "/",
|
|
6330
|
+
requestHeaders: req.headers,
|
|
6331
|
+
requestBody: null,
|
|
6332
|
+
statusCode: res.statusCode,
|
|
6333
|
+
responseHeaders: outgoingToIncoming(res.getHeaders()),
|
|
6334
|
+
responseBody: resChunks.length > 0 ? Buffer.concat(resChunks) : null,
|
|
6335
|
+
responseContentType: String(res.getHeader("content-type") ?? ""),
|
|
6336
|
+
startTime,
|
|
6337
|
+
config: { maxBodyCapture: DEFAULT_MAX_BODY_CAPTURE }
|
|
6338
|
+
});
|
|
6339
|
+
} catch {
|
|
6326
6340
|
}
|
|
6327
|
-
const result = originalEnd.apply(this, [chunk, ...args]);
|
|
6328
|
-
defaultStore.capture({
|
|
6329
|
-
requestId,
|
|
6330
|
-
method,
|
|
6331
|
-
url: req.url ?? "/",
|
|
6332
|
-
requestHeaders: req.headers,
|
|
6333
|
-
requestBody: reqChunks.length > 0 ? Buffer.concat(reqChunks) : null,
|
|
6334
|
-
statusCode: res.statusCode,
|
|
6335
|
-
responseHeaders: outgoingToIncoming(res.getHeaders()),
|
|
6336
|
-
responseBody: resChunks.length > 0 ? Buffer.concat(resChunks) : null,
|
|
6337
|
-
responseContentType: String(res.getHeader("content-type") ?? ""),
|
|
6338
|
-
startTime,
|
|
6339
|
-
config: { maxBodyCapture: DEFAULT_MAX_BODY_CAPTURE }
|
|
6340
|
-
});
|
|
6341
6341
|
return result;
|
|
6342
6342
|
};
|
|
6343
6343
|
}
|
package/package.json
CHANGED