proteum 2.1.2 → 2.1.6
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/AGENTS.md +22 -14
- package/README.md +112 -17
- package/agents/project/AGENTS.md +188 -25
- package/agents/project/CODING_STYLE.md +1 -0
- package/agents/project/client/AGENTS.md +13 -8
- package/agents/project/client/pages/AGENTS.md +17 -9
- package/agents/project/diagnostics.md +52 -0
- package/agents/project/optimizations.md +48 -0
- package/agents/project/server/routes/AGENTS.md +9 -6
- package/agents/project/server/services/AGENTS.md +10 -6
- package/agents/project/tests/AGENTS.md +11 -5
- package/cli/app/config.ts +13 -14
- package/cli/app/index.ts +58 -0
- package/cli/commands/command.ts +8 -0
- package/cli/commands/connect.ts +45 -0
- package/cli/commands/dev.ts +26 -11
- package/cli/commands/diagnose.ts +286 -0
- package/cli/commands/doctor.ts +18 -5
- package/cli/commands/explain.ts +25 -0
- package/cli/commands/perf.ts +243 -0
- package/cli/commands/session.ts +254 -0
- package/cli/commands/sessionLocalRunner.js +188 -0
- package/cli/commands/trace.ts +17 -1
- package/cli/commands/verify.ts +281 -0
- package/cli/compiler/artifacts/connectedProjects.ts +453 -0
- package/cli/compiler/artifacts/controllers.ts +198 -49
- package/cli/compiler/artifacts/discovery.ts +0 -34
- package/cli/compiler/artifacts/manifest.ts +90 -6
- package/cli/compiler/artifacts/routing.ts +2 -2
- package/cli/compiler/artifacts/services.ts +277 -130
- package/cli/compiler/client/index.ts +3 -0
- package/cli/compiler/common/files/style.ts +52 -0
- package/cli/compiler/common/generatedRouteModules.ts +34 -5
- package/cli/compiler/common/scripts.ts +11 -5
- package/cli/compiler/index.ts +2 -1
- package/cli/compiler/server/index.ts +3 -0
- package/cli/presentation/commands.ts +136 -7
- package/cli/presentation/devSession.ts +32 -7
- package/cli/runtime/commands.ts +193 -6
- package/cli/scaffold/index.ts +14 -25
- package/cli/scaffold/templates.ts +41 -27
- package/cli/utils/agents.ts +4 -2
- package/cli/utils/keyboard.ts +8 -0
- package/client/dev/profiler/ApexChart.tsx +66 -0
- package/client/dev/profiler/index.tsx +2798 -417
- package/client/dev/profiler/runtime.noop.ts +12 -0
- package/client/dev/profiler/runtime.ts +195 -4
- package/client/services/router/request/api.ts +6 -1
- package/common/applicationConfig.ts +173 -0
- package/common/applicationConfigLoader.ts +102 -0
- package/common/connectedProjects.ts +113 -0
- package/common/dev/connect.ts +267 -0
- package/common/dev/console.ts +31 -0
- package/common/dev/contractsDoctor.ts +128 -0
- package/common/dev/diagnostics.ts +59 -15
- package/common/dev/inspection.ts +491 -0
- package/common/dev/performance.ts +809 -0
- package/common/dev/profiler.ts +3 -0
- package/common/dev/proteumManifest.ts +31 -6
- package/common/dev/requestTrace.ts +56 -1
- package/common/dev/session.ts +24 -0
- package/common/env/proteumEnv.ts +176 -50
- package/common/router/index.ts +1 -0
- package/common/router/request/api.ts +2 -0
- package/config.ts +5 -0
- package/docs/dev-commands.md +5 -1
- package/docs/dev-sessions.md +90 -0
- package/docs/diagnostics.md +74 -11
- package/docs/request-tracing.md +50 -3
- package/package.json +1 -1
- package/server/app/container/config.ts +16 -87
- package/server/app/container/console/index.ts +42 -8
- package/server/app/container/index.ts +3 -1
- package/server/app/container/trace/index.ts +153 -0
- package/server/app/devDiagnostics.ts +138 -0
- package/server/app/index.ts +18 -8
- package/server/app/service/container.ts +0 -12
- package/server/app/service/index.ts +0 -2
- package/server/services/prisma/index.ts +121 -4
- package/server/services/router/http/index.ts +352 -0
- package/server/services/router/index.ts +50 -47
- package/server/services/router/request/api.ts +160 -19
- package/server/services/router/request/index.ts +8 -0
- package/server/services/router/response/index.ts +24 -1
- package/server/services/router/response/page/document.tsx +5 -0
- package/server/services/router/response/page/index.tsx +10 -0
- package/agents/framework/AGENTS.md +0 -177
- package/server/services/auth/router/service.json +0 -6
- package/server/services/auth/service.json +0 -6
- package/server/services/cron/service.json +0 -6
- package/server/services/disks/drivers/local/service.json +0 -6
- package/server/services/disks/drivers/s3/service.json +0 -6
- package/server/services/disks/service.json +0 -6
- package/server/services/fetch/service.json +0 -7
- package/server/services/prisma/service.json +0 -6
- package/server/services/router/service.json +0 -6
- package/server/services/schema/router/service.json +0 -6
- package/server/services/schema/service.json +0 -6
- package/server/services/security/encrypt/aes/service.json +0 -6
package/docs/dev-commands.md
CHANGED
|
@@ -67,13 +67,17 @@ In `proteum dev`, the bottom profiler exposes a `Commands` tab.
|
|
|
67
67
|
- it shows the backing class, method, scope, and source location
|
|
68
68
|
- clicking `Run now` executes the command through the running dev server
|
|
69
69
|
- the last result or error stays attached to that command row in the panel
|
|
70
|
+
- it now adds scope, execution-duration, and status charts over the same command definitions and latest execution snapshots
|
|
70
71
|
|
|
71
72
|
The profiler also exposes the shared diagnostics surfaces for humans:
|
|
72
73
|
|
|
73
74
|
- `Explain` renders the same manifest-backed data as `proteum explain`
|
|
74
75
|
- `Doctor` renders the same manifest diagnostics as `proteum doctor`
|
|
76
|
+
- `Diagnose` renders the same owner, suspect, contract, trace-summary, and buffered-log view as `proteum diagnose`
|
|
77
|
+
- `Perf` renders the same hot-path, request-waterfall, compare, and memory views as `proteum perf`
|
|
78
|
+
- the other profiler tabs now add focused visual charts over the same trace, manifest, and dev-runtime contracts instead of only row lists
|
|
75
79
|
|
|
76
|
-
For the shared diagnostics contract and the corresponding dev HTTP endpoints, see [diagnostics.md](diagnostics.md).
|
|
80
|
+
For the shared diagnostics contract, trace-derived perf contract, and the corresponding dev HTTP endpoints, see [diagnostics.md](diagnostics.md) and [request-tracing.md](request-tracing.md).
|
|
77
81
|
|
|
78
82
|
### HTTP Endpoints
|
|
79
83
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Dev Sessions
|
|
2
|
+
|
|
3
|
+
Proteum ships a dev-only auth bootstrap command so agents, Playwright runs, and local debugging can start from an authenticated state without driving the login UI.
|
|
4
|
+
|
|
5
|
+
## When To Use It
|
|
6
|
+
|
|
7
|
+
Use `proteum session` when:
|
|
8
|
+
|
|
9
|
+
- a protected page, controller, or manual route must be exercised in dev
|
|
10
|
+
- an LLM agent or browser automation needs an authenticated cookie quickly
|
|
11
|
+
- you want to reproduce role-gated behavior with a known user account
|
|
12
|
+
|
|
13
|
+
Do not use it when:
|
|
14
|
+
|
|
15
|
+
- the login or signup flow itself is under test
|
|
16
|
+
- you are validating third-party auth redirects or callback handling
|
|
17
|
+
- you do not know which user should be used for the scenario
|
|
18
|
+
|
|
19
|
+
## CLI
|
|
20
|
+
|
|
21
|
+
Local mode:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
proteum session admin@example.com --role ADMIN
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Remote mode against an existing dev server:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
proteum session admin@example.com --role ADMIN --port 3101
|
|
31
|
+
proteum session god@example.com --role GOD --url http://localhost:3102 --json
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Behavior:
|
|
35
|
+
|
|
36
|
+
- local mode refreshes generated artifacts, builds the dev output, starts a temporary local dev server, creates the session, prints the payload, and exits
|
|
37
|
+
- remote mode talks to an already running `proteum dev` instance
|
|
38
|
+
- the command requires an explicit email and optionally asserts a role before returning the session
|
|
39
|
+
- the command is available only in dev mode
|
|
40
|
+
|
|
41
|
+
## Output Contract
|
|
42
|
+
|
|
43
|
+
The JSON payload includes:
|
|
44
|
+
|
|
45
|
+
- `baseUrl`
|
|
46
|
+
- `user`
|
|
47
|
+
- `session.token`
|
|
48
|
+
- `session.cookieName`
|
|
49
|
+
- `session.issuedAt`
|
|
50
|
+
- `session.expiresAt`
|
|
51
|
+
- `browserCookie`
|
|
52
|
+
- `curlCookieHeader`
|
|
53
|
+
- `playwright.cookies`
|
|
54
|
+
|
|
55
|
+
Playwright usage:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
await browserContext.addCookies(output.playwright.cookies);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
HTTP usage:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
curl -H "$(jq -r '.curlCookieHeader' session.json)" http://localhost:3101/api/Auth/CurrentUser
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Agent Guidance
|
|
68
|
+
|
|
69
|
+
- Prefer `proteum session` over UI login automation when the goal is to test or debug protected application behavior.
|
|
70
|
+
- Use UI login automation only when the auth UX itself is the feature under test.
|
|
71
|
+
- Pair it with `proteum diagnose` for a fast protected-route summary, `proteum perf request` for a one-request timing breakdown, then use `proteum trace` when you need lower-level request events.
|
|
72
|
+
|
|
73
|
+
Typical flow:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
proteum trace arm --capture deep --port 3101
|
|
77
|
+
proteum session admin@example.com --role ADMIN --port 3101 --json > session.json
|
|
78
|
+
# add the returned cookie in Playwright, then load the protected page once
|
|
79
|
+
proteum diagnose /dashboard --port 3101
|
|
80
|
+
proteum perf request /dashboard --port 3101
|
|
81
|
+
proteum trace latest --port 3101
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Dev HTTP Endpoint
|
|
85
|
+
|
|
86
|
+
The CLI uses the same dev-only endpoint exposed by the running app:
|
|
87
|
+
|
|
88
|
+
- `POST /__proteum/session/start`
|
|
89
|
+
|
|
90
|
+
This endpoint exists only in dev mode and is not available in production.
|
package/docs/diagnostics.md
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
# Diagnostics and Explainability
|
|
2
2
|
|
|
3
|
-
Proteum exposes two manifest-backed diagnostics surfaces:
|
|
3
|
+
Proteum exposes two manifest-backed diagnostics surfaces plus one composite request-diagnosis surface:
|
|
4
4
|
|
|
5
5
|
- `proteum explain`: inspect the generated app structure
|
|
6
6
|
- `proteum doctor`: inspect manifest diagnostics
|
|
7
|
+
- `proteum diagnose`: combine owner lookup, diagnostics, matching request traces, and buffered server logs for one concrete query or path
|
|
7
8
|
|
|
8
|
-
These are not separate models for different tools.
|
|
9
|
+
These are not separate models for different tools. `explain` and `doctor` share the same generated manifest snapshot, while `diagnose` layers live dev-only request data on top of that same framework view.
|
|
10
|
+
|
|
11
|
+
Performance inspection is a sibling surface, not a separate instrumentation stack: `proteum perf` and the profiler `Perf` tab aggregate the same dev-only request traces that back `proteum trace`.
|
|
9
12
|
|
|
10
13
|
## Shared Contract
|
|
11
14
|
|
|
12
15
|
The canonical snapshot lives in `./.proteum/manifest.json`.
|
|
13
16
|
|
|
14
|
-
Proteum uses that same manifest in
|
|
17
|
+
Proteum uses that same manifest in six places:
|
|
15
18
|
|
|
16
19
|
- `proteum explain` for human-readable and `--json` output
|
|
17
20
|
- `proteum doctor` for human-readable and `--json` output
|
|
18
|
-
-
|
|
19
|
-
-
|
|
21
|
+
- `proteum explain owner <query>` for ownership lookup over the manifest index
|
|
22
|
+
- `proteum doctor --contracts` for generated-artifact and manifest-owned source validation on disk
|
|
23
|
+
- the dev-only `__proteum/explain*` and `__proteum/doctor*` HTTP endpoints
|
|
24
|
+
- the `Explain`, `Doctor`, and `Diagnose` tabs in the bottom profiler during `proteum dev`
|
|
20
25
|
|
|
21
|
-
This means the CLI, the dev HTTP endpoints, and the profiler all describe the same
|
|
26
|
+
This means the CLI, the dev HTTP endpoints, and the profiler all describe the same framework-owned snapshot before any live trace or log overlays are added.
|
|
22
27
|
|
|
23
|
-
If a command such as `proteum explain`, `proteum doctor`, or `proteum refresh` regenerates `.proteum/manifest.json`, the next CLI call, HTTP call, or profiler refresh will reflect that same updated snapshot.
|
|
28
|
+
If a command such as `proteum explain`, `proteum doctor`, `proteum diagnose`, or `proteum refresh` regenerates `.proteum/manifest.json`, the next CLI call, HTTP call, or profiler refresh will reflect that same updated snapshot.
|
|
24
29
|
|
|
25
30
|
## CLI
|
|
26
31
|
|
|
@@ -28,12 +33,23 @@ Common usage:
|
|
|
28
33
|
|
|
29
34
|
```bash
|
|
30
35
|
proteum explain
|
|
36
|
+
proteum explain owner /api/Auth/CurrentUser
|
|
31
37
|
proteum explain --routes --controllers --commands
|
|
32
38
|
proteum explain --all --json
|
|
33
39
|
|
|
34
40
|
proteum doctor
|
|
41
|
+
proteum doctor --contracts
|
|
35
42
|
proteum doctor --json
|
|
36
43
|
proteum doctor --strict
|
|
44
|
+
|
|
45
|
+
proteum diagnose /
|
|
46
|
+
proteum diagnose /dashboard --port 3101
|
|
47
|
+
proteum diagnose /api/Auth/CurrentUser --url http://127.0.0.1:3101
|
|
48
|
+
|
|
49
|
+
proteum perf top --since today
|
|
50
|
+
proteum perf request /dashboard --port 3101
|
|
51
|
+
proteum perf compare --baseline yesterday --target today --group-by route
|
|
52
|
+
proteum perf memory --since 1h --group-by controller
|
|
37
53
|
```
|
|
38
54
|
|
|
39
55
|
`proteum explain --json` emits the selected manifest sections as machine-readable JSON.
|
|
@@ -45,12 +61,37 @@ proteum doctor --strict
|
|
|
45
61
|
- `summary.strictFailed`
|
|
46
62
|
- `diagnostics`
|
|
47
63
|
|
|
64
|
+
`proteum diagnose` emits a composite response with:
|
|
65
|
+
|
|
66
|
+
- `owner`
|
|
67
|
+
- `doctor`
|
|
68
|
+
- `contracts`
|
|
69
|
+
- `request`
|
|
70
|
+
- `attribution`
|
|
71
|
+
- `suspects`
|
|
72
|
+
- `serverLogs`
|
|
73
|
+
|
|
74
|
+
`proteum perf` emits trace-derived performance views:
|
|
75
|
+
|
|
76
|
+
- `top`: grouped hot paths with avg, p95, CPU, SQL, render, and heap deltas
|
|
77
|
+
- `request`: one traced request waterfall with stage timings, CPU, SQL, render, self time, and payload sizes
|
|
78
|
+
- `compare`: grouped baseline vs target deltas
|
|
79
|
+
- `memory`: grouped heap and RSS drift summaries
|
|
80
|
+
|
|
48
81
|
## Dev HTTP Endpoints
|
|
49
82
|
|
|
50
83
|
In `profile: dev`, the running app exposes:
|
|
51
84
|
|
|
52
85
|
- `GET /__proteum/explain`
|
|
86
|
+
- `GET /__proteum/explain/owner`
|
|
53
87
|
- `GET /__proteum/doctor`
|
|
88
|
+
- `GET /__proteum/doctor/contracts`
|
|
89
|
+
- `GET /__proteum/logs`
|
|
90
|
+
- `GET /__proteum/diagnose`
|
|
91
|
+
- `GET /__proteum/perf/top`
|
|
92
|
+
- `GET /__proteum/perf/compare`
|
|
93
|
+
- `GET /__proteum/perf/memory`
|
|
94
|
+
- `GET /__proteum/perf/request`
|
|
54
95
|
|
|
55
96
|
`/__proteum/explain` supports optional section selection:
|
|
56
97
|
|
|
@@ -59,12 +100,28 @@ GET /__proteum/explain?sections=routes,controllers,commands
|
|
|
59
100
|
GET /__proteum/explain?section=env§ion=diagnostics
|
|
60
101
|
```
|
|
61
102
|
|
|
103
|
+
`/__proteum/explain/owner` supports a single query:
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
GET /__proteum/explain/owner?query=/api/Auth/CurrentUser
|
|
107
|
+
```
|
|
108
|
+
|
|
62
109
|
`/__proteum/doctor` supports optional strict mode:
|
|
63
110
|
|
|
64
111
|
```text
|
|
65
112
|
GET /__proteum/doctor?strict=true
|
|
66
113
|
```
|
|
67
114
|
|
|
115
|
+
`/__proteum/doctor/contracts` supports the same optional strict mode.
|
|
116
|
+
|
|
117
|
+
`/__proteum/diagnose` supports a concrete query or request target:
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
GET /__proteum/diagnose?query=/dashboard&path=/dashboard
|
|
121
|
+
GET /__proteum/diagnose?requestId=<requestId>
|
|
122
|
+
GET /__proteum/diagnose?query=/api/Auth/CurrentUser&logsLevel=warn&logsLimit=40
|
|
123
|
+
```
|
|
124
|
+
|
|
68
125
|
These endpoints are intended for local tooling and are not available in production.
|
|
69
126
|
|
|
70
127
|
## Profiler
|
|
@@ -73,8 +130,11 @@ During `proteum dev`, the bottom profiler is the human-facing UI over the same d
|
|
|
73
130
|
|
|
74
131
|
- `Explain` calls `/__proteum/explain`
|
|
75
132
|
- `Doctor` calls `/__proteum/doctor`
|
|
133
|
+
- `Diagnose` calls `/__proteum/diagnose` and renders the same owner, diagnostics, suspect, and log summary that the CLI uses
|
|
134
|
+
- `Perf` calls the `/__proteum/perf/*` endpoints and renders the same grouped rollups and current-request waterfall that `proteum perf` uses, plus visual charts for hot paths, time breakdowns, regression deltas, and memory drift
|
|
76
135
|
- `Commands` uses the dev command endpoints
|
|
77
|
-
- `
|
|
136
|
+
- `Summary`, `Auth`, `Routing`, `Controller`, `SSR`, `API`, `SQL`, `Errors`, `Diagnose`, `Explain`, `Doctor`, `Commands`, and `Cron` now layer focused charts over the same trace and diagnostics contracts instead of only showing rows
|
|
137
|
+
- `Timeline` remains the primary waterfall and event-stream inspection surface
|
|
78
138
|
|
|
79
139
|
Use the profiler when a human needs to browse the same data that an agent or CLI command can already inspect directly.
|
|
80
140
|
|
|
@@ -83,6 +143,9 @@ Use the profiler when a human needs to browse the same data that an agent or CLI
|
|
|
83
143
|
For AI coding agents or automation:
|
|
84
144
|
|
|
85
145
|
1. Read `./.proteum/manifest.json` or run `proteum explain --json`.
|
|
86
|
-
2. Run `proteum doctor --json` to inspect framework diagnostics.
|
|
87
|
-
3.
|
|
88
|
-
4.
|
|
146
|
+
2. Run `proteum doctor --json` and `proteum doctor --contracts --json` to inspect framework and generated-artifact diagnostics.
|
|
147
|
+
3. Run `proteum explain owner <query>` when you need to map a route, controller path, or generated artifact back to source.
|
|
148
|
+
4. For concrete request-time behavior, start with `proteum diagnose <path> --port <port>`.
|
|
149
|
+
5. For performance, CPU, SQL, render, or memory questions, use `proteum perf top|request|compare|memory` against the same running dev server.
|
|
150
|
+
6. Use `proteum trace ...` when you need lower-level event detail than `diagnose` or `perf` provides.
|
|
151
|
+
7. Open the profiler only when a human-readable view helps; it should agree with the CLI after refresh.
|
package/docs/request-tracing.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Request Tracing
|
|
2
2
|
|
|
3
|
-
Proteum ships with a dev-only in-memory request trace buffer so routing, controller execution, SSR,
|
|
3
|
+
Proteum ships with a dev-only in-memory request trace buffer so routing, controller execution, SSR, API, Prisma SQL, render behavior, and request-time performance can be inspected without attaching a debugger or scattering temporary logs through the runtime.
|
|
4
4
|
|
|
5
5
|
## Scope
|
|
6
6
|
|
|
7
7
|
- tracing is available only when the app runs with `profile: dev`
|
|
8
|
-
- traces are exposed through `proteum trace` and the dev-only `__proteum/trace` HTTP endpoints
|
|
9
|
-
-
|
|
8
|
+
- traces are exposed through `proteum trace`, `proteum perf`, and the dev-only `__proteum/trace` and `__proteum/perf` HTTP endpoints
|
|
9
|
+
- `proteum diagnose` is a separate composite surface that reads the same framework diagnostics plus one matching request trace and buffered server logs; see [diagnostics.md](diagnostics.md)
|
|
10
10
|
- production requests are not traced by this feature
|
|
11
11
|
|
|
12
12
|
## Main Commands
|
|
@@ -18,6 +18,11 @@ proteum trace show <requestId>
|
|
|
18
18
|
proteum trace arm --capture deep
|
|
19
19
|
proteum trace export <requestId>
|
|
20
20
|
proteum trace latest --url http://127.0.0.1:3010
|
|
21
|
+
|
|
22
|
+
proteum perf top --since today
|
|
23
|
+
proteum perf request /dashboard --port 3103
|
|
24
|
+
proteum perf compare --baseline yesterday --target today --group-by route
|
|
25
|
+
proteum perf memory --since 1h --group-by controller
|
|
21
26
|
```
|
|
22
27
|
|
|
23
28
|
Before reproducing a bug or starting a new test pass:
|
|
@@ -37,6 +42,19 @@ proteum trace show <requestId> --port 3103
|
|
|
37
42
|
|
|
38
43
|
Use `--url http://host:port` when the dev server is reachable on a non-standard host and `--port` is not enough.
|
|
39
44
|
|
|
45
|
+
If the request under test is protected and login UX is not the feature under test, mint an auth cookie with `proteum session <email> --role <role>` before reproducing the request. This keeps the trace focused on the protected behavior instead of the login flow.
|
|
46
|
+
|
|
47
|
+
If you already know the failing path and want a one-shot suspect list before reading raw events, start with `proteum diagnose <path> --port <port>` and drop into `proteum trace show <requestId>` only when the lower-level event stream is still needed.
|
|
48
|
+
|
|
49
|
+
Trace summaries include `sql=<count>`. Detailed trace output includes both a `Calls` section for API/fetcher activity and a `SQL` section for captured Prisma queries.
|
|
50
|
+
|
|
51
|
+
`proteum perf` is a grouped view over the same trace store:
|
|
52
|
+
|
|
53
|
+
- `top` ranks routes, concrete paths, or controllers by avg, p95, CPU, SQL, render, self time, and heap delta
|
|
54
|
+
- `request` shows one traced request waterfall with stage timings plus the hottest calls and SQL
|
|
55
|
+
- `compare` shows baseline-vs-target regressions between trace windows such as `yesterday` and `today`
|
|
56
|
+
- `memory` shows grouped heap and RSS drift trends
|
|
57
|
+
|
|
40
58
|
## What Gets Recorded
|
|
41
59
|
|
|
42
60
|
Depending on capture mode, traces can include:
|
|
@@ -46,12 +64,29 @@ Depending on capture mode, traces can include:
|
|
|
46
64
|
- direct controller route matches
|
|
47
65
|
- route resolution start, match, and deep-mode skip reasons
|
|
48
66
|
- controller start and result shape
|
|
67
|
+
- synchronous SSR fetcher calls, API batch fetchers, and async request traces
|
|
68
|
+
- Prisma SQL queries with caller method/path, optional fetcher attribution, SQL text, params, kind, operation, and timing
|
|
49
69
|
- created router/context keys
|
|
50
70
|
- setup output keys and page data summaries
|
|
51
71
|
- SSR payload shape and serialized byte size
|
|
52
72
|
- render start/end timings and document output sizes
|
|
73
|
+
- per-request CPU usage deltas plus heap and RSS snapshots before and after the request
|
|
53
74
|
- normalized request errors
|
|
54
75
|
|
|
76
|
+
## SQL Tracing
|
|
77
|
+
|
|
78
|
+
Prisma query tracing covers both ORM operations and raw queries.
|
|
79
|
+
|
|
80
|
+
- `kind` is recorded as `orm` or `raw`
|
|
81
|
+
- `operation` records the Prisma operation such as `findFirst`, `count`, or `$queryRawUnsafe`
|
|
82
|
+
- `model` is recorded when Prisma exposes one
|
|
83
|
+
- `callerMethod` and `callerPath` attach the query to the request that triggered it
|
|
84
|
+
- when the query runs inside an SSR fetcher or an API batch fetcher, the trace also records the fetcher id/label and call id
|
|
85
|
+
- `durationMs`, `startedAt`, and `finishedAt` come from Prisma query events
|
|
86
|
+
- `query`, `paramsText`, and parsed `paramsJson` are stored for inspection
|
|
87
|
+
|
|
88
|
+
This currently covers SQL issued through Proteum's Prisma service, including raw helpers that flow through the same Prisma client.
|
|
89
|
+
|
|
55
90
|
## Capture Modes
|
|
56
91
|
|
|
57
92
|
- `summary`: smallest capture, focused on request lifecycle and high-signal events
|
|
@@ -64,8 +99,16 @@ Use `deep` selectively. It is for one-off investigation, not continuous capture.
|
|
|
64
99
|
|
|
65
100
|
During `proteum dev`, the bottom profiler renders the same live request traces.
|
|
66
101
|
|
|
102
|
+
- `Summary` charts recent duration, workload, route frequency, and status trends for the captured sessions
|
|
67
103
|
- `Timeline` shows the full request event stream
|
|
68
104
|
- `Auth` filters the selected session down to auth-specific events so matched rules, tracking, and allow/deny outcomes can be inspected without scanning unrelated events
|
|
105
|
+
- `Routing`, `Controller`, and `SSR` add focused charts over resolve, controller lifecycle, render, and payload data for the selected trace
|
|
106
|
+
- `API` shows synchronous SSR/API fetcher calls plus async requests, with workload and status charts above the waterfall
|
|
107
|
+
- `SQL` shows captured Prisma queries grouped by caller, with workload, operation, and heatmap charts plus a waterfall and detail sidebar
|
|
108
|
+
- `Errors` adds grouped source and error-family charts over the captured failures
|
|
109
|
+
- `Diagnose` combines the selected request summary with explain/doctor/contracts data and buffered server logs, plus visual suspect, owner, and severity charts
|
|
110
|
+
- `Explain`, `Doctor`, `Commands`, and `Cron` render the same manifest and dev-runtime contracts as their CLI surfaces with matching summary charts
|
|
111
|
+
- `Perf` renders the same top, request, compare, and memory rollups exposed by `proteum perf`, with visual charts for hot-path latency, time composition, regressions, and memory drift
|
|
69
112
|
- expanding an auth event shows the summarized detail payload exactly as stored in the trace
|
|
70
113
|
|
|
71
114
|
## Configuration
|
|
@@ -128,5 +171,9 @@ These endpoints back the CLI:
|
|
|
128
171
|
- `GET /__proteum/trace/latest`
|
|
129
172
|
- `GET /__proteum/trace/requests/:id`
|
|
130
173
|
- `POST /__proteum/trace/arm`
|
|
174
|
+
- `GET /__proteum/perf/top`
|
|
175
|
+
- `GET /__proteum/perf/compare`
|
|
176
|
+
- `GET /__proteum/perf/memory`
|
|
177
|
+
- `GET /__proteum/perf/request`
|
|
131
178
|
|
|
132
179
|
The CLI should be the primary interface. Use the HTTP endpoints when you need direct machine access from another local dev tool.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proteum",
|
|
3
3
|
"description": "LLM-first Opinionated Typescript Framework for web applications.",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.6",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/proteum.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -7,11 +7,9 @@
|
|
|
7
7
|
Because it's imported by the CLI, which should be independant of the app escept for loading config
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
// Npm
|
|
11
|
-
import fs from 'fs-extra';
|
|
12
|
-
import yaml from 'yaml';
|
|
13
|
-
|
|
14
10
|
// Types
|
|
11
|
+
import type { TApplicationIdentityConfig, TApplicationSetupConfig } from '../../../common/applicationConfig';
|
|
12
|
+
import { loadApplicationIdentityConfig, loadApplicationSetupConfig } from '../../../common/applicationConfigLoader';
|
|
15
13
|
import { parseProteumEnvConfig, type TProteumLoadedEnvConfig } from '../../../common/env/proteumEnv';
|
|
16
14
|
|
|
17
15
|
declare const PROTEUM_PORT_OVERRIDE: number | null;
|
|
@@ -27,6 +25,7 @@ declare global {
|
|
|
27
25
|
|
|
28
26
|
type Env = TEnvConfig;
|
|
29
27
|
type Identity = AppIdentityConfig;
|
|
28
|
+
type Setup = AppSetupConfig;
|
|
30
29
|
interface Services {}
|
|
31
30
|
}
|
|
32
31
|
}
|
|
@@ -34,31 +33,10 @@ declare global {
|
|
|
34
33
|
export type TEnvName = TEnvConfig['name'];
|
|
35
34
|
export type TEnvConfig = TProteumLoadedEnvConfig;
|
|
36
35
|
|
|
37
|
-
type AppIdentityConfig =
|
|
38
|
-
|
|
39
|
-
identifier: string;
|
|
40
|
-
description: string;
|
|
41
|
-
author: { name: string; url: string; email: string };
|
|
42
|
-
|
|
43
|
-
social: {};
|
|
44
|
-
|
|
45
|
-
locale: string;
|
|
46
|
-
language: string;
|
|
47
|
-
maincolor: string;
|
|
48
|
-
iconsPack?: string;
|
|
49
|
-
|
|
50
|
-
web: {
|
|
51
|
-
title: string;
|
|
52
|
-
titleSuffix: string;
|
|
53
|
-
fullTitle: string;
|
|
54
|
-
description: string;
|
|
55
|
-
version: string;
|
|
56
|
-
metas?: { [name: string]: string };
|
|
57
|
-
jsonld?: { [name: string]: string };
|
|
58
|
-
};
|
|
59
|
-
};
|
|
36
|
+
type AppIdentityConfig = TApplicationIdentityConfig;
|
|
37
|
+
type AppSetupConfig = TApplicationSetupConfig;
|
|
60
38
|
|
|
61
|
-
export type AppConfig = { env: Config.Env; identity: Config.Identity };
|
|
39
|
+
export type AppConfig = { env: Config.Env; identity: Config.Identity; setup: Config.Setup };
|
|
62
40
|
|
|
63
41
|
const debug = false;
|
|
64
42
|
|
|
@@ -77,78 +55,29 @@ export default class ConfigParser {
|
|
|
77
55
|
public envName?: string,
|
|
78
56
|
) {}
|
|
79
57
|
|
|
80
|
-
private loadYaml(filepath: string) {
|
|
81
|
-
debug && console.info(`Loading config ${filepath}`);
|
|
82
|
-
const rawConfig = fs.readFileSync(filepath, 'utf-8');
|
|
83
|
-
return yaml.parse(rawConfig);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
58
|
public env(): TEnvConfig {
|
|
87
59
|
debug && console.info('[app] Loading Proteum env vars from process.env');
|
|
60
|
+
const setup = this.setup();
|
|
88
61
|
|
|
89
62
|
return {
|
|
90
63
|
...parseProteumEnvConfig({
|
|
91
64
|
appDir: this.appDir,
|
|
65
|
+
connectedProjects: setup.connect,
|
|
92
66
|
routerPortOverride: getRouterPortOverride(),
|
|
93
67
|
}),
|
|
94
68
|
version: BUILD_DATE,
|
|
95
69
|
};
|
|
96
70
|
}
|
|
97
71
|
|
|
98
|
-
public identity() {
|
|
99
|
-
const identityFile = this.appDir + '/identity.
|
|
72
|
+
public identity(): Config.Identity {
|
|
73
|
+
const identityFile = this.appDir + '/identity.config.ts';
|
|
100
74
|
debug && console.info(`Loading identity ${identityFile}`);
|
|
101
|
-
return this.
|
|
75
|
+
return loadApplicationIdentityConfig(this.appDir);
|
|
102
76
|
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/*const walkYaml = (dir: string, configA: any, envName: string) => {
|
|
106
|
-
|
|
107
|
-
const files = fs.readdirSync(dir);
|
|
108
|
-
for (const file of files) {
|
|
109
|
-
|
|
110
|
-
const fullpath = dir + '/' + file;
|
|
111
|
-
|
|
112
|
-
// extension .yaml
|
|
113
|
-
const isDir = fs.lstatSync(fullpath).isDirectory();
|
|
114
|
-
let key = file;
|
|
115
|
-
if (!isDir) {
|
|
116
|
-
|
|
117
|
-
if (!file.endsWith('.yaml'))
|
|
118
|
-
continue;
|
|
119
|
-
|
|
120
|
-
key = key.substring(0, key.length - 5);
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
let fileConfig = configA;
|
|
125
|
-
|
|
126
|
-
// Ciblage environnement
|
|
127
|
-
// Before: /config/services/env.<envName>.yaml
|
|
128
|
-
// After: /config/services
|
|
129
|
-
if (key.startsWith('env.')) {
|
|
130
|
-
|
|
131
|
-
// Excluding not mtching env name
|
|
132
|
-
if (key.substring(4) !== envName)
|
|
133
|
-
continue;
|
|
134
|
-
|
|
135
|
-
// Créé l'entrée dans la config, sauf si le nom du fichier est default
|
|
136
|
-
} else if (key !== 'default') {
|
|
137
|
-
|
|
138
|
-
// Init config
|
|
139
|
-
if (!(key in fileConfig))
|
|
140
|
-
fileConfig[key] = {};
|
|
141
|
-
|
|
142
|
-
fileConfig = configA[key];
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Recursion
|
|
147
|
-
if (isDir)
|
|
148
|
-
walk(fullpath, fileConfig, envName);
|
|
149
|
-
// Lecture fichier
|
|
150
|
-
else
|
|
151
|
-
deepExtend(fileConfig, loadYaml(fullpath));
|
|
152
77
|
|
|
78
|
+
public setup(): Config.Setup {
|
|
79
|
+
const setupFile = this.appDir + '/proteum.config.ts';
|
|
80
|
+
debug && console.info(`Loading setup ${setupFile}`);
|
|
81
|
+
return loadApplicationSetupConfig(this.appDir);
|
|
153
82
|
}
|
|
154
|
-
}
|
|
83
|
+
}
|
|
@@ -16,7 +16,9 @@ import Ansi2Html from 'ansi-to-html';
|
|
|
16
16
|
// Core libs
|
|
17
17
|
import type ApplicationContainer from '..';
|
|
18
18
|
import context from '@server/context';
|
|
19
|
+
import type { TDevConsoleLogChannel, TDevConsoleLogEntry, TDevConsoleLogLevel } from '@common/dev/console';
|
|
19
20
|
import type { ServerBug, TCatchedError } from '@common/errors';
|
|
21
|
+
import type { TTraceCallOrigin, TTraceSqlQueryKind } from '@common/dev/requestTrace';
|
|
20
22
|
import type ServerRequest from '@server/services/router/request';
|
|
21
23
|
|
|
22
24
|
/*----------------------------------
|
|
@@ -36,14 +38,9 @@ export type Services = {};
|
|
|
36
38
|
- TYPES
|
|
37
39
|
----------------------------------*/
|
|
38
40
|
|
|
39
|
-
export type ChannelInfos = {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
method?: string;
|
|
44
|
-
path?: string;
|
|
45
|
-
|
|
46
|
-
user?: string;
|
|
41
|
+
export type ChannelInfos = TDevConsoleLogChannel & {
|
|
42
|
+
traceCallOrigin?: TTraceCallOrigin;
|
|
43
|
+
prismaOperations?: Array<{ kind: TTraceSqlQueryKind; model?: string; operation: string }>;
|
|
47
44
|
};
|
|
48
45
|
|
|
49
46
|
export type TGuestLogs = {
|
|
@@ -233,6 +230,43 @@ export default class Console {
|
|
|
233
230
|
return logLevels[logLevelName];
|
|
234
231
|
}
|
|
235
232
|
|
|
233
|
+
private serializeLogChannel(channel: ChannelInfos): TDevConsoleLogChannel {
|
|
234
|
+
return {
|
|
235
|
+
channelType: channel.channelType,
|
|
236
|
+
...(typeof channel.channelId === 'string' ? { channelId: channel.channelId } : {}),
|
|
237
|
+
...(typeof channel.method === 'string' ? { method: channel.method } : {}),
|
|
238
|
+
...(typeof channel.path === 'string' ? { path: channel.path } : {}),
|
|
239
|
+
...(typeof channel.user === 'string' ? { user: channel.user } : {}),
|
|
240
|
+
...(typeof channel.traceCallId === 'string' ? { traceCallId: channel.traceCallId } : {}),
|
|
241
|
+
...(typeof channel.traceCallOrigin === 'string' ? { traceCallOrigin: channel.traceCallOrigin } : {}),
|
|
242
|
+
...(typeof channel.traceCallLabel === 'string' ? { traceCallLabel: channel.traceCallLabel } : {}),
|
|
243
|
+
...(typeof channel.traceCallFetcherId === 'string' ? { traceCallFetcherId: channel.traceCallFetcherId } : {}),
|
|
244
|
+
...(Array.isArray(channel.prismaOperations)
|
|
245
|
+
? {
|
|
246
|
+
prismaOperations: channel.prismaOperations.map((operation) => ({
|
|
247
|
+
kind: operation.kind,
|
|
248
|
+
...(typeof operation.model === 'string' ? { model: operation.model } : {}),
|
|
249
|
+
operation: operation.operation,
|
|
250
|
+
})),
|
|
251
|
+
}
|
|
252
|
+
: {}),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
public listLogs(limit = 100, minimumLevel: TDevConsoleLogLevel = 'log'): TDevConsoleLogEntry[] {
|
|
257
|
+
const minimumLogLevel = logLevels[minimumLevel];
|
|
258
|
+
|
|
259
|
+
return this.logs
|
|
260
|
+
.filter((entry) => logLevels[entry.level] >= minimumLogLevel)
|
|
261
|
+
.slice(-Math.max(0, limit))
|
|
262
|
+
.map((entry) => ({
|
|
263
|
+
channel: this.serializeLogChannel(entry.channel),
|
|
264
|
+
level: entry.level,
|
|
265
|
+
text: formatWithOptions({ breakLength: 120, colors: false, depth: 3 }, ...entry.args),
|
|
266
|
+
time: entry.time.toISOString(),
|
|
267
|
+
}));
|
|
268
|
+
}
|
|
269
|
+
|
|
236
270
|
private clean() {
|
|
237
271
|
if (this.config.debug) {
|
|
238
272
|
console.log(
|
|
@@ -29,6 +29,7 @@ export class ApplicationContainer<TServicesIndex extends StartedServicesIndex =
|
|
|
29
29
|
public Services = Services as ServicesContainer<TServicesIndex>;
|
|
30
30
|
public Environment: TEnvConfig;
|
|
31
31
|
public Identity: Config.Identity;
|
|
32
|
+
public Setup: Config.Setup;
|
|
32
33
|
public Console: Console;
|
|
33
34
|
public Trace: Trace;
|
|
34
35
|
|
|
@@ -53,7 +54,8 @@ export class ApplicationContainer<TServicesIndex extends StartedServicesIndex =
|
|
|
53
54
|
const configParser = new ConfigParser(this.path.root);
|
|
54
55
|
this.Environment = configParser.env();
|
|
55
56
|
this.Identity = configParser.identity();
|
|
56
|
-
this.
|
|
57
|
+
this.Setup = configParser.setup();
|
|
58
|
+
this.Console = new Console(this, { ...defaultConsoleConfig, enable: this.Environment.profile === 'dev' });
|
|
57
59
|
this.Trace = new Trace(this, this.Environment.trace);
|
|
58
60
|
}
|
|
59
61
|
|