nestjs-profiler 1.0.26 → 1.0.28

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 CHANGED
@@ -4,112 +4,202 @@
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
- A NestJS module for profiling HTTP requests, database queries, cache operations, outbound HTTP calls, application logs, package health, code quality, and event tracking. Inspired by Symfony Profiler, it provides a web-based dashboard to inspect everything that happens inside a request — from DB queries to downstream API calls — in real time.
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
- ## Features
14
+ > A drop-in debugging dashboard for NestJS. Inspect HTTP requests, database queries, outbound calls, logs, events, scheduled jobs, memory usage, and code health — all from one browser tab, with zero instrumentation required.
10
15
 
11
- - **HTTP Request Tracing** — Tracks method, URL, controller handler, duration, status code, headers, and request body.
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
- ## Installation
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
- ### Peer Dependencies (Optional)
30
+ **2. Register in your AppModule**
40
31
 
41
- Install only the dependencies relevant to your project:
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
+ ### Memory Monitor
110
+ Continuously samples Node.js heap statistics using `process.memoryUsage()` and `v8.getHeapStatistics()` (zero extra dependencies). Stores a 60-sample rolling window (10 minutes at 10-second intervals) and computes a 0–100 leak score from three signals: heap growth rate across the window, number of V8 detached contexts, and sustained growth ratio. Trend is classified as `stable`, `growing`, or `likely_leak`.
111
+
112
+ - **Live heap chart** — SVG line chart of `heapUsed` across the rolling window, auto-refreshes every 15 seconds
113
+ - **Stat cards** — heap used, heap total, RSS, detached contexts, and heap size limit
114
+ - **Leak score ring** — 0–100 circular gauge with score breakdown by component
115
+ - **Per-request memory delta** — every intercepted request records `heapUsed` before and after the handler; the top 20 highest-delta requests are shown in a table
116
+ - **Force GC** — manually triggers garbage collection (requires `--expose-gc`, pre-wired in `start:dev`)
117
+ - **Heap Snapshot** — generates a V8 heap snapshot and streams it directly to the browser as a `.heapsnapshot` download; open in Chrome DevTools → Memory tab → Load for a full object-level leak analysis
118
+
119
+ **Leak score breakdown:**
120
+
121
+ | Component | Max pts | Signal |
122
+ |---|---|---|
123
+ | Growth rate | 40 | `(avg second half − avg first half) / avg first half` of rolling window |
124
+ | Detached contexts | 40 | `numberOfDetachedContexts × 8` from V8 GC metadata |
125
+ | Sustained growth | 20 | Fraction of 10s intervals where heap grew (>70% = full 20 pts) |
126
+
127
+ Score < 30 → `stable` · 30–59 or growth ≥ 5% → `growing` · ≥ 60 or growth ≥ 15% → `likely_leak`
128
+
129
+ **Enabling GC and snapshots in development:**
130
+
131
+ The `start:dev`, `start:debug`, and `start:prod` scripts all pass `--expose-gc` automatically. If you run Node directly:
132
+
133
+ ```bash
134
+ node --expose-gc dist/main
135
+ ```
136
+
137
+ ### Security
138
+ - **Dashboard Authentication** — optional login wall with HMAC-SHA256 tokens stored in `localStorage`, 24-hour TTL. No separate auth server needed
139
+
140
+ ---
141
+
142
+ ## Installation
42
143
 
43
144
  ```bash
44
- # For PostgreSQL
45
- npm install pg
145
+ npm install nestjs-profiler
146
+ ```
46
147
 
47
- # For MongoDB
48
- npm install mongodb
148
+ ### Optional Peer Dependencies
49
149
 
50
- # For MySQL
51
- npm install mysql2
150
+ Install only what your project uses:
52
151
 
53
- # For Cache Profiling
54
- npm install @nestjs/cache-manager cache-manager
152
+ ```bash
153
+ npm install pg # PostgreSQL
154
+ npm install mongodb # MongoDB
155
+ npm install mysql2 # MySQL
156
+ npm install @nestjs/cache-manager cache-manager # Cache profiling
157
+ npm install @nestjs/event-emitter # Event tracking
158
+ npm install @nestjs/schedule # Scheduled jobs
55
159
  ```
56
160
 
161
+ ---
162
+
57
163
  ## Configuration
58
164
 
59
- Import `ProfilerModule` in your root `AppModule`:
165
+ All options are passed to `ProfilerModule.forRoot()`. Only `enabled` is required everything else is opt-in.
60
166
 
61
167
  ```typescript
62
- import { Module } from '@nestjs/common';
63
168
  import { ProfilerModule } from 'nestjs-profiler';
64
169
  import * as pg from 'pg';
65
170
 
66
171
  @Module({
67
172
  imports: [
68
173
  ProfilerModule.forRoot({
69
- // Global enable/disable (default: true)
70
- // Recommended: disable in production
71
174
  enabled: process.env.NODE_ENV !== 'production',
72
175
 
73
- // ── Database ─────────────────────────────────────────────────
74
- // PostgreSQL — pass the pg driver instance
176
+ // PostgreSQL
75
177
  pgDriver: pg,
76
178
  collectQueries: true,
77
-
78
- // Auto-Explain for slow queries
79
179
  explain: {
80
180
  enabled: true,
81
- thresholdMs: 50, // Only explain queries taking > 50ms
82
- analyze: false, // true = EXPLAIN ANALYZE (actually executes!)
181
+ thresholdMs: 100, // explain queries slower than this
182
+ analyze: false, // true = EXPLAIN ANALYZE (executes the query!)
83
183
  },
84
184
 
85
- // MongoDB — pass the mongodb driver instance
185
+ // MongoDB
86
186
  mongoDriver: require('mongodb'),
87
187
  collectMongo: true,
88
188
 
89
- // MySQL — pass the mysql2 driver instance
189
+ // MySQL
90
190
  mysqlDriver: require('mysql2'),
91
191
  collectMysql: true,
92
192
 
93
- // ── Outbound HTTP ─────────────────────────────────────────────
94
- // Tracks all outbound http/https calls made during each request.
95
- // Enabled by default — set false to disable.
193
+ // Outbound HTTP (on by default)
96
194
  collectHttp: true,
97
195
 
98
- // ── Cache ─────────────────────────────────────────────────────
99
- collectCache: true, // requires @nestjs/cache-manager
196
+ // Cache
197
+ collectCache: true,
100
198
 
101
- // ── Logs ──────────────────────────────────────────────────────
199
+ // Logs
102
200
  collectLogs: true,
103
201
 
104
- // ── Storage ───────────────────────────────────────────────────
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.
202
+ // Auth (off by default)
113
203
  auth: {
114
204
  enabled: true,
115
205
  username: 'admin',
@@ -121,68 +211,69 @@ import * as pg from 'pg';
121
211
  export class AppModule {}
122
212
  ```
123
213
 
124
- ### Default behaviour
214
+ ### Options Reference
125
215
 
126
- | Option | Default | Notes |
216
+ | Option | Default | Description |
127
217
  |---|---|---|
128
- | `enabled` | `true` | Set `false` or tie to `NODE_ENV` |
129
- | `collectHttp` | `true` | Patches `http`/`https` automatically |
130
- | `collectLogs` | `true` | |
131
- | `collectQueries` | `true` | Requires `pgDriver` / `mongoDriver` / `mysqlDriver` |
132
- | `collectCache` | `true` | Requires `@nestjs/cache-manager` |
133
- | `explain.enabled` | `false` | Opt-in only |
134
- | Event Tracking | automatic | Active when `@nestjs/event-emitter` is detected |
135
- | `auth.enabled` | `false` | When `true`, `username` and `password` are required |
136
-
137
- ## Usage
138
-
139
- ### 1. Initialize Explorers (Optional but Recommended)
140
-
141
- To enable the **Entity Explorer** and **Route Explorer**, call `initialize` in `main.ts` after creating the app:
142
-
143
- ```typescript
144
- import { NestFactory } from '@nestjs/core';
145
- import { AppModule } from './app.module';
146
- import { ProfilerModule } from 'nestjs-profiler';
147
-
148
- async function bootstrap() {
149
- const app = await NestFactory.create(AppModule);
150
-
151
- ProfilerModule.initialize(app);
152
-
153
- await app.listen(3000);
154
- }
155
- bootstrap();
156
- ```
218
+ | `enabled` | `true` | Master switch. Tie to `NODE_ENV` in production |
219
+ | `collectHttp` | `true` | Outbound HTTP tracking (patches `http`/`https`) |
220
+ | `collectLogs` | `true` | Log capture per request |
221
+ | `collectQueries` | `true` | DB query capture. Requires a driver to be passed |
222
+ | `collectCache` | `true` | Cache op tracking. Requires `@nestjs/cache-manager` |
223
+ | `explain.enabled` | `false` | Auto-Explain for slow queries |
224
+ | `explain.thresholdMs` | `100` | Minimum query duration to trigger explain |
225
+ | `explain.analyze` | `false` | Run `EXPLAIN ANALYZE` instead of `EXPLAIN` |
226
+ | `auth.enabled` | `false` | Enable login wall. `username` and `password` required when `true` |
227
+ | Event Tracking | automatic | Activates when `@nestjs/event-emitter` is detected |
228
+ | Scheduled Jobs | automatic | Activates when `@nestjs/schedule` is detected |
157
229
 
158
- ### 2. Accessing the Dashboard
230
+ ---
159
231
 
160
- Once configured, start your application. The profiler automatically intercepts all requests.
232
+ ## Dashboard
161
233
 
162
- Navigate to `http://localhost:3000/__profiler`.
234
+ Navigate to `/__profiler` after starting your app.
163
235
 
164
- #### Dashboard Pages
165
-
166
- | Path | Description |
236
+ | Page | Description |
167
237
  |---|---|
168
- | `/__profiler` | Redirects to Summary (default landing page) |
169
238
  | `/__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 database queries across requests, sorted by duration |
172
- | `/__profiler/view/http-calls` | All outbound HTTP calls across requests, sorted by duration |
239
+ | `/__profiler/view/requests` | All captured requests with status, duration, and method |
240
+ | `/__profiler/view/queries` | All DB queries across requests, sortable by duration |
241
+ | `/__profiler/view/http-calls` | All outbound HTTP calls, sortable by duration |
173
242
  | `/__profiler/view/logs` | Paginated application logs |
174
- | `/__profiler/view/logs/live` | Live streaming terminal — real-time log output |
243
+ | `/__profiler/view/logs/live` | Real-time streaming log terminal |
175
244
  | `/__profiler/view/cache` | Cache operations with hit/miss breakdown |
176
- | `/__profiler/view/entities` | Registered database entities |
177
- | `/__profiler/view/routes` | All registered application routes |
245
+ | `/__profiler/view/entities` | Registered database entities and their columns |
246
+ | `/__profiler/view/routes` | All registered routes with DTOs and parameter types |
178
247
  | `/__profiler/view/health` | Package vulnerabilities and outdated dependency report |
179
- | `/__profiler/view/code-quality` | ESLint and TypeScript static analysis report |
180
- | `/__profiler/view/events` | Event tracking — cascading tree of all `EventEmitter2` emissions |
248
+ | `/__profiler/view/code-quality` | ESLint and TypeScript static analysis |
249
+ | `/__profiler/view/events` | Event cascade tree for `EventEmitter2` emissions |
250
+ | `/__profiler/view/cron-jobs` | Live scheduled job monitor — cron, intervals, and timeouts |
251
+ | `/__profiler/view/memory` | Heap monitor — live chart, leak score, per-request memory deltas, GC and snapshot controls |
181
252
  | `/__profiler/:id` | Full detail view for a single request |
182
253
 
183
- ### 3. Dashboard Authentication
254
+ ### JSON API
255
+
256
+ All data is also available as JSON for programmatic use:
257
+
258
+ ```
259
+ GET /__profiler/json # all captured requests
260
+ GET /__profiler/:id/json # single request detail
261
+ GET /__profiler/api/health # package health (5 min cache)
262
+ GET /__profiler/api/health?force=true
263
+ GET /__profiler/api/code-quality # static analysis (5 min cache)
264
+ GET /__profiler/api/code-quality?force=true
265
+ GET /__profiler/api/events # event log (live, not cached)
266
+ GET /__profiler/api/cron-jobs # scheduled job state (live, not cached)
267
+ GET /__profiler/api/memory # current heap report + leak score + top request deltas
268
+ POST /__profiler/api/memory/gc # force GC (requires --expose-gc)
269
+ POST /__profiler/api/memory/snapshot # generate and download a .heapsnapshot file
270
+ ```
271
+
272
+ ---
184
273
 
185
- By default the profiler dashboard is open to anyone who can reach the server. For shared or remote environments you can enable a login wall:
274
+ ## Feature Guides
275
+
276
+ ### Dashboard Authentication
186
277
 
187
278
  ```typescript
188
279
  ProfilerModule.forRoot({
@@ -194,177 +285,145 @@ ProfilerModule.forRoot({
194
285
  })
195
286
  ```
196
287
 
197
- TypeScript enforces that `username` and `password` are both present when `enabled: true` setting `enabled: true` without credentials is a compile-time error.
198
-
199
- **How it works:**
288
+ 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
289
 
201
- When auth is enabled, every `/__profiler` page runs a blocking script before rendering. If no valid token is found in `localStorage`, the browser is immediately redirected to `/__profiler/login`. After a successful login the token is stored in `localStorage.__profiler_auth` and is valid for 24 hours, after which the user is redirected to the login page again.
290
+ TypeScript enforces that `username` and `password` are present when `enabled: true`. Omitting either is a compile-time error.
202
291
 
203
- Token generation uses HMAC-SHA256 keyed on the password, so tokens are invalidated automatically if the password changes.
292
+ > Auth is enforced client-side. It prevents casual access on shared dev/staging environments but is not a security boundary for sensitive data.
204
293
 
205
- | Route | Description |
294
+ | Route | Purpose |
206
295
  |---|---|
207
296
  | `GET /__profiler/login` | Login page |
208
- | `POST /__profiler/api/login` | JSON login endpoint returns `{ token, expiresAt }` |
209
- | `GET /__profiler/logout` | Clears the token and redirects to the login page |
297
+ | `POST /__profiler/api/login` | Validates credentials, returns a session token |
298
+ | `GET /__profiler/logout` | Clears the token and redirects to login |
210
299
 
211
- > **Note:** Auth is enforced client-side via `localStorage`. It is intended to prevent casual access in shared dev/staging environments, not as a security boundary for sensitive data. Do not expose the profiler on a public network regardless of this setting.
300
+ ---
212
301
 
213
- ### 4. Outbound HTTP Tracking
302
+ ### Event Tracking
214
303
 
215
- Outbound HTTP tracking is **enabled by default**. Any `http.request`, `https.request`, `http.get`, or `https.get` call made during a request is automatically captured — including calls made via axios, node-fetch, and similar libraries.
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:
304
+ Requires `@nestjs/event-emitter`:
229
305
 
230
306
  ```typescript
231
- ProfilerModule.forRoot({ collectHttp: false })
232
- ```
233
-
234
- ### 5. Package Health
307
+ import { EventEmitterModule } from '@nestjs/event-emitter';
235
308
 
236
- The Health tab runs `npm audit` and `npm outdated` from your project root and displays the results in a searchable UI.
309
+ @Module({
310
+ imports: [EventEmitterModule.forRoot()],
311
+ })
312
+ export class AppModule {}
313
+ ```
237
314
 
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.
315
+ 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.
243
316
 
244
- #### JSON endpoint
317
+ **Example what you see in the dashboard:**
245
318
 
246
319
  ```
247
- GET /__profiler/api/health # cached result (5 min TTL)
248
- GET /__profiler/api/health?force=true # force fresh scan
320
+ 🔔 order.created (async) ⬆ OrderService.createOrder 145ms
321
+ onOrderCreated [InventoryListener] 45ms
322
+ ✓ onOrderCreated [InvoiceListener] 80ms
323
+ ✓ onOrderCreated [AuditListener] 5ms
324
+ └── 🔔 inventory.reserved ⬆ InventoryListener 23ms
325
+ ✓ onInventoryReserved [NotificationListener] 20ms
326
+ └── 🔔 invoice.created ⬆ InvoiceListener 4ms
327
+ ✓ onInvoiceCreated [AuditListener] 3ms
249
328
  ```
250
329
 
251
- ### 6. Code Quality
330
+ ---
252
331
 
253
- The Code Quality tab runs static analysis tools against your source code and surfaces every issue without AI or external services.
332
+ ### Scheduled Jobs
254
333
 
255
- **ESLint** — uses your project's existing ESLint configuration (`node_modules/.bin/eslint`). Results are shown in two views:
334
+ Requires `@nestjs/schedule`:
256
335
 
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.
336
+ ```bash
337
+ npm install @nestjs/schedule
338
+ ```
259
339
 
260
- **TypeScript** — runs `tsc --noEmit` using your project's `tsconfig.json`. Each error links to `typescript.tv/errors` for explanations.
340
+ ```typescript
341
+ import { ScheduleModule } from '@nestjs/schedule';
261
342
 
262
- **Summary cards** show total issues, errors, warnings, auto-fixable count, and files affected at a glance.
343
+ @Module({
344
+ imports: [ScheduleModule.forRoot()],
345
+ })
346
+ export class AppModule {}
347
+ ```
263
348
 
264
- File paths have a **copy-to-clipboard** button that appears on hover, making it easy to jump to the file in your editor.
349
+ The profiler detects `SchedulerRegistry` at startup via `ProfilerModule.initialize(app)` no additional configuration needed. The dashboard has three tabs:
265
350
 
266
- Results are cached for 5 minutes. Click **Re-run** to force a fresh analysis.
351
+ **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.
267
352
 
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.
353
+ **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.
269
354
 
270
- #### JSON endpoint
355
+ **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.
271
356
 
272
- ```
273
- GET /__profiler/api/code-quality # cached result (5 min TTL)
274
- GET /__profiler/api/code-quality?force=true # force fresh scan
275
- ```
357
+ All tabs auto-refresh every 15 seconds. If `@nestjs/schedule` is not installed, the page shows an install prompt instead of an error.
276
358
 
277
- ### 7. Event Tracking
359
+ **Example:**
278
360
 
279
- The Event Tracking tab captures every `EventEmitter2` emission across your application and renders it as a cascading tree — no instrumentation required.
361
+ ```typescript
362
+ import { Cron, CronExpression, Interval, Timeout } from '@nestjs/schedule';
280
363
 
281
- **What it captures:**
364
+ @Injectable()
365
+ export class TasksService {
282
366
 
283
- - The event name and a JSON preview of the payload
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
367
+ @Cron(CronExpression.EVERY_MINUTE, { name: 'health-ping' })
368
+ handleHealthPing() { /* ... */ }
290
369
 
291
- **Example chain visualised:**
370
+ @Cron('0 0 * * *', { name: 'nightly-cleanup' })
371
+ handleNightlyCleanup() { /* ... */ }
292
372
 
293
- ```
294
- 🔔 order.created (async) OrderService.createOrder 145ms
295
- ✓ onOrderCreated [InventoryListener] 45ms
296
- onOrderCreated [InvoiceListener] 80ms
297
- onOrderCreated [AuditListener] 5ms
298
- └── 🔔 inventory.reserved (async) ⬆ InventoryListener.onOrderCreated 23ms
299
- ✓ onInventoryReserved [NotificationListener] 20ms
300
- ✓ onInventoryReserved [AuditListener] 3ms
301
- └── 🔔 invoice.created (async) ⬆ InvoiceListener.onOrderCreated 4ms
302
- ✓ onInvoiceCreated [AuditListener] 3ms
373
+ @Interval('metrics-flush', 30_000)
374
+ handleMetricsFlush() { /* ... */ }
375
+
376
+ @Timeout('deferred-init', 10_000)
377
+ handleDeferredInit() { /* ... */ }
378
+ }
303
379
  ```
304
380
 
305
- **Requirements:** `@nestjs/event-emitter` must be installed and `EventEmitterModule.forRoot()` must be imported in your `AppModule`. The profiler detects it automatically — no configuration needed.
381
+ ---
306
382
 
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.
383
+ ### Memory Monitor
308
384
 
309
- Results are not cached each refresh fetches the latest events from the in-memory ring buffer (last 500 events).
385
+ No configuration neededthe Memory Monitor starts automatically when the profiler is enabled. It polls every 10 seconds and becomes meaningful after roughly 2 minutes of uptime (20 samples).
310
386
 
311
- #### JSON endpoint
387
+ Navigate to `/__profiler/view/memory` to see the live dashboard.
312
388
 
313
- ```
314
- GET /__profiler/api/events # all captured events (flat array, newest first)
315
- ```
389
+ **Force GC** triggers `global.gc()` if Node was started with `--expose-gc`. The `start:dev`, `start:debug`, and `start:prod` scripts in this package include the flag automatically. If you manage your own start command:
316
390
 
317
- ### 8. Route Explorer
391
+ ```bash
392
+ node --expose-gc dist/main
393
+ ```
318
394
 
319
- The Route Explorer (`/__profiler/view/routes`) lists every registered route in your application. Routes are grouped by controller and displayed in an expandable accordion. Call `ProfilerModule.initialize(app)` in `main.ts` to populate it (see section 1).
395
+ **Heap Snapshot** generates a V8 heap snapshot on the server, streams it directly to your browser as a file download, and deletes the temp file. To analyse it:
320
396
 
321
- **Per-route information:**
397
+ 1. Open Chrome DevTools
398
+ 2. Go to the **Memory** tab
399
+ 3. Click the **Load** icon (folder button at the top)
400
+ 4. Select the downloaded `.heapsnapshot` file
322
401
 
323
- Each route row shows the HTTP method badge and the full path (including any global prefix). Expanding a row reveals:
402
+ The snapshot shows every object in the heap retained size, shallow size, constructor name, distance from GC root — searchable and filterable. Useful for identifying *what* is leaking after the Memory Monitor tells you *that* something is leaking.
324
403
 
325
- - **Path parameters** — parameters from the URL pattern (`:id`, `:userId`, etc.), detected either from `@Param('name')` decorators or by scanning the path template directly.
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.
404
+ **Reading the leak score:**
330
405
 
331
- **Example what gets surfaced:**
406
+ Trigger a few demo patterns (if you have the demo module enabled) and watch the score climb in real time:
332
407
 
333
408
  ```
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]
409
+ POST /demo/memory/leak/array # unbounded array — grows heapUsed
410
+ POST /demo/memory/leak/listeners # orphaned listeners — raises detached contexts
411
+ POST /demo/memory/leak/cache # unbounded Map — slow steady growth
412
+ DELETE /demo/memory/leak/all # clear everything
342
413
  ```
343
414
 
344
- The explorer performs a best-effort scan using `reflect-metadata`. It works with TypeScript's `emitDecoratorMetadata: true` (standard for NestJS projects) and does not require OpenAPI/Swagger to be installed.
345
-
346
- ### 9. JSON API
415
+ ---
347
416
 
348
- Retrieve profile data programmatically:
417
+ ### Route Explorer
349
418
 
350
- - `GET /__profiler/json` List all captured requests
351
- - `GET /__profiler/:id/json` — Details for a specific request
352
-
353
- ## Global Prefix
354
-
355
- If your app uses a global prefix (e.g. `/api`), exclude the profiler routes:
356
-
357
- ```typescript
358
- app.setGlobalPrefix('api', {
359
- exclude: [{ path: '__profiler/(.*)', method: RequestMethod.ALL }],
360
- });
361
- ```
419
+ Populated by `ProfilerModule.initialize(app)`. Lists every route grouped by controller in an expandable accordion. Each route surfaces:
362
420
 
363
- ## Important Notes
421
+ - HTTP method and full path (including global prefix)
422
+ - Path parameters, query parameters, and headers with their TypeScript types
423
+ - Body DTO — class name, all decorated properties and types (discovered via `reflect-metadata`)
424
+ - Source file path with a one-click copy button
364
425
 
365
- - The profiler is designed for **development and debugging only**. Do not enable in production it adds request overhead and exposes internal application data.
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).
426
+ Works with `emitDecoratorMetadata: true` (standard in NestJS). No OpenAPI/Swagger required.
368
427
 
369
428
  ## License
370
429