nestjs-profiler 1.0.26 → 1.0.27
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 +228 -235
- package/controllers/profiler.controller.d.ts +5 -1
- package/controllers/profiler.controller.js +30 -4
- package/controllers/profiler.controller.js.map +1 -1
- package/package.json +1 -1
- package/profiler.module.js +25 -1
- package/profiler.module.js.map +1 -1
- package/services/cron-explorer.service.d.ts +48 -0
- package/services/cron-explorer.service.js +260 -0
- package/services/cron-explorer.service.js.map +1 -0
- package/services/view.service.js +2 -0
- package/services/view.service.js.map +1 -1
- package/views/cron-jobs.html +635 -0
- package/views/layout.html +10 -1
package/README.md
CHANGED
|
@@ -4,112 +4,174 @@
|
|
|
4
4
|
<img src="https://raw.githubusercontent.com/MohammedRaslan/Nest-JS-Profiler/refs/heads/main/libs/nestjs-profiler/src/assets/logo.png" width="400" alt="NestJS Profiler Logo" />
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/nestjs-profiler"><img src="https://img.shields.io/npm/v/nestjs-profiler.svg" alt="npm version" /></a>
|
|
9
|
+
<a href="https://www.npmjs.com/package/nestjs-profiler"><img src="https://img.shields.io/npm/dm/nestjs-profiler.svg" alt="npm downloads" /></a>
|
|
10
|
+
<img src="https://img.shields.io/badge/node-%3E%3D16-brightgreen" alt="node version" />
|
|
11
|
+
<img src="https://img.shields.io/badge/license-MIT-blue" alt="license" />
|
|
12
|
+
</p>
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
> A drop-in debugging dashboard for NestJS. Inspect HTTP requests, database queries, outbound calls, logs, events, scheduled jobs, and code health — all from one browser tab, with zero instrumentation required.
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
- **Database Profiling**
|
|
13
|
-
- **PostgreSQL** — Captures all queries via `pg` (compatible with TypeORM, MikroORM, raw pg). Supports **Auto-Explain** to run `EXPLAIN` or `EXPLAIN ANALYZE` on slow queries automatically.
|
|
14
|
-
- **MongoDB** — Profiles MongoDB commands and queries.
|
|
15
|
-
- **MySQL** — Profiles MySQL queries.
|
|
16
|
-
- **N+1 Detection** — Automatically flags repeated identical queries within the same request.
|
|
17
|
-
- **Slow Query Tagging** — Tags queries exceeding 100ms.
|
|
18
|
-
- **Sequential Scan Detection** — Tags queries using a Seq Scan from the explain plan.
|
|
19
|
-
- **Outbound HTTP Tracking** — Captures every outbound `http`/`https` call made during a request: URL, method, status code, duration, and headers. Works automatically with axios, node-fetch, and any library built on Node's `http`/`https` modules. Enabled by default — no configuration required.
|
|
20
|
-
- **Cache Profiling** — Tracks cache operations (get, set, del, reset) and hit/miss ratio when using `@nestjs/cache-manager`.
|
|
21
|
-
- **Log Profiling** — Captures application logs associated with each request context.
|
|
22
|
-
- **Live Logs Terminal** — Real-time streaming log viewer at `/__profiler/view/logs/live` via Server-Sent Events. Supports level filtering, search, pause/resume, and auto-scroll.
|
|
23
|
-
- **Summary Dashboard** — Aggregate statistics: avg/p95 duration, error rate, cache hit rate, top slow endpoints, top slow queries, and recent errors.
|
|
24
|
-
- **Entity Explorer** — Lists all registered TypeORM/MikroORM entities and their columns.
|
|
25
|
-
- **Route Explorer** — Lists all registered routes with their controllers, handlers, HTTP methods, and full path. Each route expands to show path parameters, query parameters, request headers, and body DTOs — including the DTO class name, all decorated properties, and their TypeScript types. Source file paths are shown with a one-click copy button.
|
|
26
|
-
- **Dashboard Authentication** — Optional login wall protecting all `/__profiler` routes. When enabled, an HMAC-signed token is stored in the browser's `localStorage` with a 24-hour TTL. Credentials are defined in `ProfilerModule.forRoot()` — no separate auth server required.
|
|
27
|
-
- **Package Health** — Runs `npm audit` and `npm outdated` to surface known vulnerabilities and stale dependencies. Results are cached for 5 minutes. Works with npm, yarn, and pnpm. If the registry is unreachable, outdated packages are still shown with an inline warning.
|
|
28
|
-
- **Code Quality** — Runs ESLint and TypeScript compiler checks (`tsc --noEmit`) against your source code. Issues are displayed grouped by file or by rule, with direct links to ESLint rule docs and TypeScript error references. Auto-fixable issues are flagged. File paths are copyable with one click.
|
|
29
|
-
- **Event Tracking** — Automatically intercepts every `EventEmitter2` emission and builds a cascading tree showing which service fired each event, which listeners handled it (with individual timings), and any child events emitted from inside a listener. No instrumentation required — works automatically when `@nestjs/event-emitter` is installed.
|
|
30
|
-
- **Web UI** — Built-in dashboard at `/__profiler` with no external dependencies.
|
|
31
|
-
- **Zero Hard Dependencies** — Core functionality works out of the box; database drivers are optional peer dependencies.
|
|
16
|
+
---
|
|
32
17
|
|
|
33
|
-
|
|
18
|
+
> ⚠️ **Development use only.** The profiler adds request overhead and exposes internal application data. Always set `enabled: process.env.NODE_ENV !== 'production'`.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
**1. Install**
|
|
34
25
|
|
|
35
26
|
```bash
|
|
36
27
|
npm install nestjs-profiler
|
|
37
28
|
```
|
|
38
29
|
|
|
39
|
-
|
|
30
|
+
**2. Register in your AppModule**
|
|
40
31
|
|
|
41
|
-
|
|
32
|
+
```typescript
|
|
33
|
+
import { ProfilerModule } from 'nestjs-profiler';
|
|
34
|
+
|
|
35
|
+
@Module({
|
|
36
|
+
imports: [
|
|
37
|
+
ProfilerModule.forRoot({
|
|
38
|
+
enabled: process.env.NODE_ENV !== 'production',
|
|
39
|
+
}),
|
|
40
|
+
],
|
|
41
|
+
})
|
|
42
|
+
export class AppModule {}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**3. Initialize in main.ts**
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { ProfilerModule } from 'nestjs-profiler';
|
|
49
|
+
|
|
50
|
+
async function bootstrap() {
|
|
51
|
+
const app = await NestFactory.create(AppModule);
|
|
52
|
+
ProfilerModule.initialize(app); // enables Route Explorer, Entity Explorer, Scheduled Jobs
|
|
53
|
+
await app.listen(3000);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
### Global Prefix (Required if you use global route prefix)
|
|
60
|
+
|
|
61
|
+
If your app uses a global route prefix, exclude the profiler:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
app.setGlobalPrefix('api', {
|
|
65
|
+
exclude: [{ path: '__profiler/(.*)', method: RequestMethod.ALL }],
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Open `http://localhost:3000/__profiler` — the dashboard is live.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Features
|
|
74
|
+
|
|
75
|
+
### Request Profiling
|
|
76
|
+
- Traces every HTTP request: method, URL, handler, status code, duration, headers, and body
|
|
77
|
+
- Summary dashboard with avg/p95 duration, error rate, cache hit rate, top slow endpoints, and recent errors
|
|
78
|
+
- Full detail view per request including all associated queries, cache ops, logs, and outbound calls
|
|
79
|
+
|
|
80
|
+
### Database
|
|
81
|
+
- **PostgreSQL** — captures all queries via `pg`, compatible with TypeORM, MikroORM, and raw pg
|
|
82
|
+
- **MongoDB** — profiles all MongoDB commands
|
|
83
|
+
- **MySQL** — profiles MySQL queries via `mysql2`
|
|
84
|
+
- **N+1 Detection** — flags repeated identical queries within the same request
|
|
85
|
+
- **Slow Query Tagging** — highlights queries over 100ms
|
|
86
|
+
- **Sequential Scan Detection** — flags full table scans from the query explain plan
|
|
87
|
+
- **Auto-Explain** — automatically runs `EXPLAIN` or `EXPLAIN ANALYZE` on slow queries (opt-in)
|
|
88
|
+
|
|
89
|
+
### Outbound HTTP
|
|
90
|
+
Automatically captures every `http`/`https` call your app makes — including axios, node-fetch, and any library built on Node's core modules. Records method, URL, status code, duration, headers (with Authorization and Cookie values redacted), and errors. No configuration required.
|
|
91
|
+
|
|
92
|
+
### Cache
|
|
93
|
+
Tracks `get`, `set`, `del`, and `reset` operations with hit/miss ratio when using `@nestjs/cache-manager`.
|
|
94
|
+
|
|
95
|
+
### Logs
|
|
96
|
+
- Captures application logs per request context
|
|
97
|
+
- **Live Logs Terminal** — real-time streaming viewer via Server-Sent Events, with level filtering, search, pause/resume, and auto-scroll
|
|
98
|
+
|
|
99
|
+
### Code Analysis
|
|
100
|
+
- **Package Health** — runs `npm audit` and `npm outdated` to surface vulnerabilities and stale dependencies, sorted by severity
|
|
101
|
+
- **Code Quality** — runs ESLint and `tsc --noEmit` against your source. Issues shown by file or by rule, with links to rule docs and TypeScript error references. Auto-fixable issues are flagged
|
|
102
|
+
|
|
103
|
+
### Application Intelligence
|
|
104
|
+
- **Route Explorer** — every registered route grouped by controller, with path/query/header params, body DTOs, property types, and source file paths
|
|
105
|
+
- **Entity Explorer** — all registered TypeORM/MikroORM entities with their columns
|
|
106
|
+
- **Event Tracking** — intercepts every `EventEmitter2` emission and renders a cascading tree: which service fired it, which listeners handled it, individual timings, child events, and errors. Requires `@nestjs/event-emitter`
|
|
107
|
+
- **Scheduled Jobs** — live view of all `@Cron`, `@Interval`, and `@Timeout` jobs from `@nestjs/schedule`, with countdowns, last run times, cycle progress, and handler details. Requires `@nestjs/schedule`
|
|
108
|
+
|
|
109
|
+
### Security
|
|
110
|
+
- **Dashboard Authentication** — optional login wall with HMAC-SHA256 tokens stored in `localStorage`, 24-hour TTL. No separate auth server needed
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Installation
|
|
42
115
|
|
|
43
116
|
```bash
|
|
44
|
-
|
|
45
|
-
|
|
117
|
+
npm install nestjs-profiler
|
|
118
|
+
```
|
|
46
119
|
|
|
47
|
-
|
|
48
|
-
npm install mongodb
|
|
120
|
+
### Optional Peer Dependencies
|
|
49
121
|
|
|
50
|
-
|
|
51
|
-
npm install mysql2
|
|
122
|
+
Install only what your project uses:
|
|
52
123
|
|
|
53
|
-
|
|
54
|
-
npm install
|
|
124
|
+
```bash
|
|
125
|
+
npm install pg # PostgreSQL
|
|
126
|
+
npm install mongodb # MongoDB
|
|
127
|
+
npm install mysql2 # MySQL
|
|
128
|
+
npm install @nestjs/cache-manager cache-manager # Cache profiling
|
|
129
|
+
npm install @nestjs/event-emitter # Event tracking
|
|
130
|
+
npm install @nestjs/schedule # Scheduled jobs
|
|
55
131
|
```
|
|
56
132
|
|
|
133
|
+
---
|
|
134
|
+
|
|
57
135
|
## Configuration
|
|
58
136
|
|
|
59
|
-
|
|
137
|
+
All options are passed to `ProfilerModule.forRoot()`. Only `enabled` is required — everything else is opt-in.
|
|
60
138
|
|
|
61
139
|
```typescript
|
|
62
|
-
import { Module } from '@nestjs/common';
|
|
63
140
|
import { ProfilerModule } from 'nestjs-profiler';
|
|
64
141
|
import * as pg from 'pg';
|
|
65
142
|
|
|
66
143
|
@Module({
|
|
67
144
|
imports: [
|
|
68
145
|
ProfilerModule.forRoot({
|
|
69
|
-
// Global enable/disable (default: true)
|
|
70
|
-
// Recommended: disable in production
|
|
71
146
|
enabled: process.env.NODE_ENV !== 'production',
|
|
72
147
|
|
|
73
|
-
//
|
|
74
|
-
// PostgreSQL — pass the pg driver instance
|
|
148
|
+
// PostgreSQL
|
|
75
149
|
pgDriver: pg,
|
|
76
150
|
collectQueries: true,
|
|
77
|
-
|
|
78
|
-
// Auto-Explain for slow queries
|
|
79
151
|
explain: {
|
|
80
152
|
enabled: true,
|
|
81
|
-
thresholdMs:
|
|
82
|
-
analyze: false, // true = EXPLAIN ANALYZE (
|
|
153
|
+
thresholdMs: 100, // explain queries slower than this
|
|
154
|
+
analyze: false, // true = EXPLAIN ANALYZE (executes the query!)
|
|
83
155
|
},
|
|
84
156
|
|
|
85
|
-
// MongoDB
|
|
157
|
+
// MongoDB
|
|
86
158
|
mongoDriver: require('mongodb'),
|
|
87
159
|
collectMongo: true,
|
|
88
160
|
|
|
89
|
-
// MySQL
|
|
161
|
+
// MySQL
|
|
90
162
|
mysqlDriver: require('mysql2'),
|
|
91
163
|
collectMysql: true,
|
|
92
164
|
|
|
93
|
-
//
|
|
94
|
-
// Tracks all outbound http/https calls made during each request.
|
|
95
|
-
// Enabled by default — set false to disable.
|
|
165
|
+
// Outbound HTTP (on by default)
|
|
96
166
|
collectHttp: true,
|
|
97
167
|
|
|
98
|
-
//
|
|
99
|
-
collectCache: true,
|
|
168
|
+
// Cache
|
|
169
|
+
collectCache: true,
|
|
100
170
|
|
|
101
|
-
//
|
|
171
|
+
// Logs
|
|
102
172
|
collectLogs: true,
|
|
103
173
|
|
|
104
|
-
//
|
|
105
|
-
// Default: in-memory (last 100 requests).
|
|
106
|
-
// Pass a custom object implementing ProfilerStorage for persistence.
|
|
107
|
-
storage: 'memory',
|
|
108
|
-
|
|
109
|
-
// ── Dashboard Auth ────────────────────────────────────────────
|
|
110
|
-
// Disabled by default. When enabled, all /__profiler routes
|
|
111
|
-
// require login. username + password are both required when
|
|
112
|
-
// enabled — a TypeScript type error is raised if either is missing.
|
|
174
|
+
// Auth (off by default)
|
|
113
175
|
auth: {
|
|
114
176
|
enabled: true,
|
|
115
177
|
username: 'admin',
|
|
@@ -121,68 +183,65 @@ import * as pg from 'pg';
|
|
|
121
183
|
export class AppModule {}
|
|
122
184
|
```
|
|
123
185
|
|
|
124
|
-
###
|
|
186
|
+
### Options Reference
|
|
125
187
|
|
|
126
|
-
| Option | Default |
|
|
188
|
+
| Option | Default | Description |
|
|
127
189
|
|---|---|---|
|
|
128
|
-
| `enabled` | `true` |
|
|
129
|
-
| `collectHttp` | `true` |
|
|
130
|
-
| `collectLogs` | `true` | |
|
|
131
|
-
| `collectQueries` | `true` | Requires
|
|
132
|
-
| `collectCache` | `true` | Requires `@nestjs/cache-manager` |
|
|
133
|
-
| `explain.enabled` | `false` |
|
|
134
|
-
|
|
|
135
|
-
| `
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
### 1. Initialize Explorers (Optional but Recommended)
|
|
190
|
+
| `enabled` | `true` | Master switch. Tie to `NODE_ENV` in production |
|
|
191
|
+
| `collectHttp` | `true` | Outbound HTTP tracking (patches `http`/`https`) |
|
|
192
|
+
| `collectLogs` | `true` | Log capture per request |
|
|
193
|
+
| `collectQueries` | `true` | DB query capture. Requires a driver to be passed |
|
|
194
|
+
| `collectCache` | `true` | Cache op tracking. Requires `@nestjs/cache-manager` |
|
|
195
|
+
| `explain.enabled` | `false` | Auto-Explain for slow queries |
|
|
196
|
+
| `explain.thresholdMs` | `100` | Minimum query duration to trigger explain |
|
|
197
|
+
| `explain.analyze` | `false` | Run `EXPLAIN ANALYZE` instead of `EXPLAIN` |
|
|
198
|
+
| `auth.enabled` | `false` | Enable login wall. `username` and `password` required when `true` |
|
|
199
|
+
| Event Tracking | automatic | Activates when `@nestjs/event-emitter` is detected |
|
|
200
|
+
| Scheduled Jobs | automatic | Activates when `@nestjs/schedule` is detected |
|
|
140
201
|
|
|
141
|
-
|
|
202
|
+
---
|
|
142
203
|
|
|
143
|
-
|
|
144
|
-
import { NestFactory } from '@nestjs/core';
|
|
145
|
-
import { AppModule } from './app.module';
|
|
146
|
-
import { ProfilerModule } from 'nestjs-profiler';
|
|
204
|
+
## Dashboard
|
|
147
205
|
|
|
148
|
-
|
|
149
|
-
const app = await NestFactory.create(AppModule);
|
|
206
|
+
Navigate to `/__profiler` after starting your app.
|
|
150
207
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
await app.listen(3000);
|
|
154
|
-
}
|
|
155
|
-
bootstrap();
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### 2. Accessing the Dashboard
|
|
159
|
-
|
|
160
|
-
Once configured, start your application. The profiler automatically intercepts all requests.
|
|
161
|
-
|
|
162
|
-
Navigate to `http://localhost:3000/__profiler`.
|
|
163
|
-
|
|
164
|
-
#### Dashboard Pages
|
|
165
|
-
|
|
166
|
-
| Path | Description |
|
|
208
|
+
| Page | Description |
|
|
167
209
|
|---|---|
|
|
168
|
-
| `/__profiler` | Redirects to Summary (default landing page) |
|
|
169
210
|
| `/__profiler/view/summary` | Aggregate stats: avg/p95 duration, error rate, top slow endpoints |
|
|
170
|
-
| `/__profiler/view/requests` | All captured requests |
|
|
171
|
-
| `/__profiler/view/queries` | All
|
|
172
|
-
| `/__profiler/view/http-calls` | All outbound HTTP calls
|
|
211
|
+
| `/__profiler/view/requests` | All captured requests with status, duration, and method |
|
|
212
|
+
| `/__profiler/view/queries` | All DB queries across requests, sortable by duration |
|
|
213
|
+
| `/__profiler/view/http-calls` | All outbound HTTP calls, sortable by duration |
|
|
173
214
|
| `/__profiler/view/logs` | Paginated application logs |
|
|
174
|
-
| `/__profiler/view/logs/live` |
|
|
215
|
+
| `/__profiler/view/logs/live` | Real-time streaming log terminal |
|
|
175
216
|
| `/__profiler/view/cache` | Cache operations with hit/miss breakdown |
|
|
176
|
-
| `/__profiler/view/entities` | Registered database entities |
|
|
177
|
-
| `/__profiler/view/routes` | All registered
|
|
217
|
+
| `/__profiler/view/entities` | Registered database entities and their columns |
|
|
218
|
+
| `/__profiler/view/routes` | All registered routes with DTOs and parameter types |
|
|
178
219
|
| `/__profiler/view/health` | Package vulnerabilities and outdated dependency report |
|
|
179
|
-
| `/__profiler/view/code-quality` | ESLint and TypeScript static analysis
|
|
180
|
-
| `/__profiler/view/events` | Event
|
|
220
|
+
| `/__profiler/view/code-quality` | ESLint and TypeScript static analysis |
|
|
221
|
+
| `/__profiler/view/events` | Event cascade tree for `EventEmitter2` emissions |
|
|
222
|
+
| `/__profiler/view/cron-jobs` | Live scheduled job monitor — cron, intervals, and timeouts |
|
|
181
223
|
| `/__profiler/:id` | Full detail view for a single request |
|
|
182
224
|
|
|
183
|
-
###
|
|
225
|
+
### JSON API
|
|
226
|
+
|
|
227
|
+
All data is also available as JSON for programmatic use:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
GET /__profiler/json # all captured requests
|
|
231
|
+
GET /__profiler/:id/json # single request detail
|
|
232
|
+
GET /__profiler/api/health # package health (5 min cache)
|
|
233
|
+
GET /__profiler/api/health?force=true
|
|
234
|
+
GET /__profiler/api/code-quality # static analysis (5 min cache)
|
|
235
|
+
GET /__profiler/api/code-quality?force=true
|
|
236
|
+
GET /__profiler/api/events # event log (live, not cached)
|
|
237
|
+
GET /__profiler/api/cron-jobs # scheduled job state (live, not cached)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
184
241
|
|
|
185
|
-
|
|
242
|
+
## Feature Guides
|
|
243
|
+
|
|
244
|
+
### Dashboard Authentication
|
|
186
245
|
|
|
187
246
|
```typescript
|
|
188
247
|
ProfilerModule.forRoot({
|
|
@@ -194,177 +253,111 @@ ProfilerModule.forRoot({
|
|
|
194
253
|
})
|
|
195
254
|
```
|
|
196
255
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
**How it works:**
|
|
256
|
+
When enabled, all `/__profiler` pages check for a valid token in `localStorage` before rendering. If none is found, the browser redirects to the login page. Tokens use HMAC-SHA256 keyed on the password and expire after 24 hours — changing the password invalidates all active sessions automatically.
|
|
200
257
|
|
|
201
|
-
|
|
258
|
+
TypeScript enforces that `username` and `password` are present when `enabled: true`. Omitting either is a compile-time error.
|
|
202
259
|
|
|
203
|
-
|
|
260
|
+
> Auth is enforced client-side. It prevents casual access on shared dev/staging environments but is not a security boundary for sensitive data.
|
|
204
261
|
|
|
205
|
-
| Route |
|
|
262
|
+
| Route | Purpose |
|
|
206
263
|
|---|---|
|
|
207
264
|
| `GET /__profiler/login` | Login page |
|
|
208
|
-
| `POST /__profiler/api/login` |
|
|
209
|
-
| `GET /__profiler/logout` | Clears the token and redirects to
|
|
265
|
+
| `POST /__profiler/api/login` | Validates credentials, returns a session token |
|
|
266
|
+
| `GET /__profiler/logout` | Clears the token and redirects to login |
|
|
210
267
|
|
|
211
|
-
|
|
268
|
+
---
|
|
212
269
|
|
|
213
|
-
###
|
|
270
|
+
### Event Tracking
|
|
214
271
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Each captured call records:
|
|
218
|
-
|
|
219
|
-
- Method and full URL
|
|
220
|
-
- HTTP vs HTTPS protocol
|
|
221
|
-
- Response status code
|
|
222
|
-
- Duration in ms
|
|
223
|
-
- Request and response headers (Authorization/Cookie values are automatically redacted)
|
|
224
|
-
- Error message if the call failed
|
|
225
|
-
|
|
226
|
-
You can view outbound calls for a specific request in the request detail view, or browse all calls across all requests at `/__profiler/view/http-calls`.
|
|
227
|
-
|
|
228
|
-
To disable:
|
|
272
|
+
Requires `@nestjs/event-emitter`:
|
|
229
273
|
|
|
230
274
|
```typescript
|
|
231
|
-
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### 5. Package Health
|
|
235
|
-
|
|
236
|
-
The Health tab runs `npm audit` and `npm outdated` from your project root and displays the results in a searchable UI.
|
|
237
|
-
|
|
238
|
-
- **Vulnerabilities** — sorted by severity (critical → high → moderate → low), with fix availability and whether the package is a direct or transitive dependency.
|
|
239
|
-
- **Outdated packages** — shows current, wanted, and latest versions with major-update warnings.
|
|
240
|
-
- Results are **cached for 5 minutes** server-side. Navigating back to the tab shows the cached result instantly without re-running. Click **Re-run audit** to force a fresh scan.
|
|
241
|
-
- If `npm audit` cannot reach the registry (e.g. VPN or proxy), the outdated packages section still renders with an inline warning for the unavailable audit.
|
|
242
|
-
- No configuration required — works automatically for npm, yarn, and pnpm projects.
|
|
243
|
-
|
|
244
|
-
#### JSON endpoint
|
|
245
|
-
|
|
246
|
-
```
|
|
247
|
-
GET /__profiler/api/health # cached result (5 min TTL)
|
|
248
|
-
GET /__profiler/api/health?force=true # force fresh scan
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### 6. Code Quality
|
|
252
|
-
|
|
253
|
-
The Code Quality tab runs static analysis tools against your source code and surfaces every issue without AI or external services.
|
|
254
|
-
|
|
255
|
-
**ESLint** — uses your project's existing ESLint configuration (`node_modules/.bin/eslint`). Results are shown in two views:
|
|
256
|
-
|
|
257
|
-
- **By File** — expandable accordion rows per file. Each issue shows line:column, severity badge, message, fix indicator (⚡ auto-fixable), and a clickable rule badge linking to the ESLint documentation.
|
|
258
|
-
- **By Rule** — sorted by severity then count, showing how many files are affected per rule.
|
|
275
|
+
import { EventEmitterModule } from '@nestjs/event-emitter';
|
|
259
276
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
File paths have a **copy-to-clipboard** button that appears on hover, making it easy to jump to the file in your editor.
|
|
265
|
-
|
|
266
|
-
Results are cached for 5 minutes. Click **Re-run** to force a fresh analysis.
|
|
267
|
-
|
|
268
|
-
> **Note:** Code Quality only lints the `src/` directory (or project root if `src/` doesn't exist) and automatically ignores `dist/`, `build/`, `coverage/`, and other generated directories.
|
|
269
|
-
|
|
270
|
-
#### JSON endpoint
|
|
271
|
-
|
|
272
|
-
```
|
|
273
|
-
GET /__profiler/api/code-quality # cached result (5 min TTL)
|
|
274
|
-
GET /__profiler/api/code-quality?force=true # force fresh scan
|
|
277
|
+
@Module({
|
|
278
|
+
imports: [EventEmitterModule.forRoot()],
|
|
279
|
+
})
|
|
280
|
+
export class AppModule {}
|
|
275
281
|
```
|
|
276
282
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
The Event Tracking tab captures every `EventEmitter2` emission across your application and renders it as a cascading tree — no instrumentation required.
|
|
280
|
-
|
|
281
|
-
**What it captures:**
|
|
283
|
+
The profiler intercepts every `emit` and `emitAsync` call automatically. No decorators or instrumentation needed. The dashboard renders a full cascade tree showing the emitter, all listeners with timings, child events, and any listener errors.
|
|
282
284
|
|
|
283
|
-
|
|
284
|
-
- Which service or function fired the event (resolved from the call stack)
|
|
285
|
-
- Each listener that handled the event, with individual execution times and pass/fail status
|
|
286
|
-
- Child events emitted from inside a listener, forming a full cascade tree
|
|
287
|
-
- The depth of each event in the chain (root = 0, emitted by a listener = 1, etc.)
|
|
288
|
-
- Whether the event was fired synchronously (`emit`) or asynchronously (`emitAsync`)
|
|
289
|
-
- Any errors thrown by a listener
|
|
290
|
-
|
|
291
|
-
**Example chain visualised:**
|
|
285
|
+
**Example — what you see in the dashboard:**
|
|
292
286
|
|
|
293
287
|
```
|
|
294
288
|
🔔 order.created (async) ⬆ OrderService.createOrder 145ms
|
|
295
289
|
✓ onOrderCreated [InventoryListener] 45ms
|
|
296
290
|
✓ onOrderCreated [InvoiceListener] 80ms
|
|
297
291
|
✓ onOrderCreated [AuditListener] 5ms
|
|
298
|
-
└── 🔔 inventory.reserved
|
|
292
|
+
└── 🔔 inventory.reserved ⬆ InventoryListener 23ms
|
|
299
293
|
✓ onInventoryReserved [NotificationListener] 20ms
|
|
300
|
-
|
|
301
|
-
└── 🔔 invoice.created (async) ⬆ InvoiceListener.onOrderCreated 4ms
|
|
294
|
+
└── 🔔 invoice.created ⬆ InvoiceListener 4ms
|
|
302
295
|
✓ onInvoiceCreated [AuditListener] 3ms
|
|
303
296
|
```
|
|
304
297
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
The page has an **Auto-refresh** toggle that polls every 3 seconds, making it easy to watch events flow in real time as you hit your endpoints.
|
|
298
|
+
---
|
|
308
299
|
|
|
309
|
-
|
|
300
|
+
### Scheduled Jobs
|
|
310
301
|
|
|
311
|
-
|
|
302
|
+
Requires `@nestjs/schedule`:
|
|
312
303
|
|
|
313
|
-
```
|
|
314
|
-
|
|
304
|
+
```bash
|
|
305
|
+
npm install @nestjs/schedule
|
|
315
306
|
```
|
|
316
307
|
|
|
317
|
-
|
|
308
|
+
```typescript
|
|
309
|
+
import { ScheduleModule } from '@nestjs/schedule';
|
|
318
310
|
|
|
319
|
-
|
|
311
|
+
@Module({
|
|
312
|
+
imports: [ScheduleModule.forRoot()],
|
|
313
|
+
})
|
|
314
|
+
export class AppModule {}
|
|
315
|
+
```
|
|
320
316
|
|
|
321
|
-
|
|
317
|
+
The profiler detects `SchedulerRegistry` at startup via `ProfilerModule.initialize(app)` — no additional configuration needed. The dashboard has three tabs:
|
|
322
318
|
|
|
323
|
-
|
|
319
|
+
**Cron Jobs** — one card per `@Cron()` method showing the expression with a plain-English translation (e.g. `0 */5 * * * *` → *Every 5 minutes*), a live next-run countdown, last run time, cycle progress bar, handler name, and source file path. An *Upcoming — next 3 hours* strip at the top plots all jobs on a shared timeline.
|
|
324
320
|
|
|
325
|
-
|
|
326
|
-
- **Query parameters** — parameters decorated with `@Query()`, with their TypeScript type.
|
|
327
|
-
- **Headers** — parameters decorated with `@Headers()`, with their TypeScript type.
|
|
328
|
-
- **Request body** — the DTO class name from `@Body()`, with an expanded table of all decorated properties and their types. Properties are discovered via `reflect-metadata` — any class using `class-validator`, `@ApiProperty`, or any other property decorator will have its fields listed automatically.
|
|
329
|
-
- **Source file** — the `.ts` file path of the DTO class, with a one-click copy button, making it easy to jump to the type definition from the profiler.
|
|
321
|
+
**Intervals** — one card per `@Interval()` method with an animated frequency ring, the repeat period displayed prominently (e.g. *Every 30s*), and fires-per-minute count.
|
|
330
322
|
|
|
331
|
-
**
|
|
323
|
+
**Timeouts** — one card per `@Timeout()` method. Pending jobs show a live countdown in amber; fired jobs turn grey with a *Fired* badge. Both show the configured delay and the handler that will run.
|
|
332
324
|
|
|
333
|
-
|
|
334
|
-
POST /api/v1/orders/:storeId
|
|
335
|
-
Path params storeId string
|
|
336
|
-
Query params includeVat boolean
|
|
337
|
-
Body (DTO) CreateOrderDto
|
|
338
|
-
items array
|
|
339
|
-
couponCode string
|
|
340
|
-
metadata object
|
|
341
|
-
src/orders/dto/create-order.dto.ts [copy]
|
|
342
|
-
```
|
|
325
|
+
All tabs auto-refresh every 15 seconds. If `@nestjs/schedule` is not installed, the page shows an install prompt instead of an error.
|
|
343
326
|
|
|
344
|
-
|
|
327
|
+
**Example:**
|
|
345
328
|
|
|
346
|
-
|
|
329
|
+
```typescript
|
|
330
|
+
import { Cron, CronExpression, Interval, Timeout } from '@nestjs/schedule';
|
|
347
331
|
|
|
348
|
-
|
|
332
|
+
@Injectable()
|
|
333
|
+
export class TasksService {
|
|
349
334
|
|
|
350
|
-
|
|
351
|
-
|
|
335
|
+
@Cron(CronExpression.EVERY_MINUTE, { name: 'health-ping' })
|
|
336
|
+
handleHealthPing() { /* ... */ }
|
|
352
337
|
|
|
353
|
-
|
|
338
|
+
@Cron('0 0 * * *', { name: 'nightly-cleanup' })
|
|
339
|
+
handleNightlyCleanup() { /* ... */ }
|
|
354
340
|
|
|
355
|
-
|
|
341
|
+
@Interval('metrics-flush', 30_000)
|
|
342
|
+
handleMetricsFlush() { /* ... */ }
|
|
356
343
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
});
|
|
344
|
+
@Timeout('deferred-init', 10_000)
|
|
345
|
+
handleDeferredInit() { /* ... */ }
|
|
346
|
+
}
|
|
361
347
|
```
|
|
362
348
|
|
|
363
|
-
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
### Route Explorer
|
|
352
|
+
|
|
353
|
+
Populated by `ProfilerModule.initialize(app)`. Lists every route grouped by controller in an expandable accordion. Each route surfaces:
|
|
354
|
+
|
|
355
|
+
- HTTP method and full path (including global prefix)
|
|
356
|
+
- Path parameters, query parameters, and headers with their TypeScript types
|
|
357
|
+
- Body DTO — class name, all decorated properties and types (discovered via `reflect-metadata`)
|
|
358
|
+
- Source file path with a one-click copy button
|
|
364
359
|
|
|
365
|
-
|
|
366
|
-
- The default in-memory storage holds the last 100 requests. Older profiles are evicted automatically.
|
|
367
|
-
- Outbound HTTP tracking patches `http`/`https` at the Node.js module level. The patch is applied once on module init and is safe for hot-reload (double-patch is guarded).
|
|
360
|
+
Works with `emitDecoratorMetadata: true` (standard in NestJS). No OpenAPI/Swagger required.
|
|
368
361
|
|
|
369
362
|
## License
|
|
370
363
|
|
|
@@ -6,6 +6,7 @@ import { EntityExplorerService } from '../services/entity-explorer.service';
|
|
|
6
6
|
import { RouteExplorerService } from '../services/route-explorer.service';
|
|
7
7
|
import { HealthService } from '../services/health.service';
|
|
8
8
|
import { CodeQualityService } from '../services/code-quality.service';
|
|
9
|
+
import { CronExplorerService } from '../services/cron-explorer.service';
|
|
9
10
|
import { ProfilerOptions } from '../common/profiler-options.interface';
|
|
10
11
|
export declare class ProfilerController {
|
|
11
12
|
private readonly profilerService;
|
|
@@ -15,8 +16,9 @@ export declare class ProfilerController {
|
|
|
15
16
|
private readonly routeExplorer;
|
|
16
17
|
private readonly healthService;
|
|
17
18
|
private readonly codeQualityService;
|
|
19
|
+
private readonly cronExplorer;
|
|
18
20
|
private readonly profilerOptions;
|
|
19
|
-
constructor(profilerService: ProfilerService, viewService: ViewService, templateBuilder: TemplateBuilderService, entityExplorer: EntityExplorerService, routeExplorer: RouteExplorerService, healthService: HealthService, codeQualityService: CodeQualityService, profilerOptions: ProfilerOptions);
|
|
21
|
+
constructor(profilerService: ProfilerService, viewService: ViewService, templateBuilder: TemplateBuilderService, entityExplorer: EntityExplorerService, routeExplorer: RouteExplorerService, healthService: HealthService, codeQualityService: CodeQualityService, cronExplorer: CronExplorerService, profilerOptions: ProfilerOptions);
|
|
20
22
|
private get authEnabled();
|
|
21
23
|
private renderLayout;
|
|
22
24
|
dashboard(res: Response): Promise<void>;
|
|
@@ -52,6 +54,8 @@ export declare class ProfilerController {
|
|
|
52
54
|
codeQualityAudit(force?: string): Promise<import("../services/code-quality.service").CodeQualityReport>;
|
|
53
55
|
eventsPage(res: Response): Promise<void>;
|
|
54
56
|
eventsApi(): Promise<import("..").EventProfile[]>;
|
|
57
|
+
cronJobsPage(res: Response): Promise<void>;
|
|
58
|
+
cronJobsApi(): Promise<import("../services/cron-explorer.service").CronReport>;
|
|
55
59
|
liveLogsPage(res: Response): Promise<void>;
|
|
56
60
|
liveLogsStream(res: Response): void;
|
|
57
61
|
serveAsset(file: string, res: Response): Promise<void>;
|