@djangocfg/monitor 2.1.216 → 2.1.218
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 +68 -246
- package/dist/client.cjs +437 -4
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +58 -1
- package/dist/client.d.ts +58 -1
- package/dist/client.mjs +456 -2
- package/dist/client.mjs.map +1 -1
- package/dist/index.cjs +1231 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1239 -0
- package/dist/index.mjs.map +1 -1
- package/dist/server.cjs +354 -3
- package/dist/server.cjs.map +1 -1
- package/dist/server.mjs +373 -1
- package/dist/server.mjs.map +1 -1
- package/package.json +16 -2
- package/src/client/MonitorProvider.tsx +43 -0
- package/src/client/index.ts +7 -1
- package/src/client/window.ts +117 -0
- package/src/index.ts +3 -2
- package/src/types/index.ts +2 -1
- package/src/.claude/.sidecar/activity.jsonl +0 -1
- package/src/.claude/.sidecar/map_cache.json +0 -38
- package/src/.claude/.sidecar/usage.json +0 -5
- package/src/.claude/project-map.md +0 -29
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# @djangocfg/monitor
|
|
2
2
|
|
|
3
|
-
Browser
|
|
4
|
-
|
|
5
|
-
**Part of [DjangoCFG](https://djangocfg.com)** — modern Django framework for production-ready SaaS applications.
|
|
3
|
+
Browser + server error monitoring SDK for [DjangoCFG](https://djangocfg.com) backends.
|
|
6
4
|
|
|
7
5
|
## Install
|
|
8
6
|
|
|
@@ -10,112 +8,27 @@ Browser error and event monitoring SDK for django-cfg backends.
|
|
|
10
8
|
pnpm add @djangocfg/monitor
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
## What's Inside
|
|
14
|
-
|
|
15
|
-
- **JS Error Capture** — `window.onerror` + `unhandledrejection` with SHA-256 fingerprinting
|
|
16
|
-
- **Console Capture** — intercepts `console.warn` / `console.error` (consola reporter or native patch)
|
|
17
|
-
- **Network Monitoring** — `monitoredFetch` wrapper reports non-2xx responses
|
|
18
|
-
- **Zod Validation Errors** — listens to `zod-validation-error` custom events (auto-integrates with `@djangocfg/api`)
|
|
19
|
-
- **Session Tracking** — anonymous `fm_session_id` UUID in localStorage + cookie
|
|
20
|
-
- **Server-side Capture** — Node.js / Edge Runtime safe, no browser APIs
|
|
21
|
-
- **Auto-flush** — batched delivery via generated API client; `KeepAliveFetchAdapter` survives page unload
|
|
22
|
-
- **Type-safe** — types generated from Django OpenAPI schema via `make gen`
|
|
23
|
-
|
|
24
11
|
## Entry Points
|
|
25
12
|
|
|
26
|
-
| Entry |
|
|
27
|
-
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
32
|
-
## Package Structure
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
src/
|
|
36
|
-
├── _api/
|
|
37
|
-
│ ├── BaseClient.ts # monitorApi singleton (MemoryStorageAdapter)
|
|
38
|
-
│ ├── index.ts # Re-exports types, enums, monitorApi
|
|
39
|
-
│ └── generated/
|
|
40
|
-
│ └── cfg_monitor/ # Auto-generated — do not edit
|
|
41
|
-
│ ├── http.ts # FetchAdapter, KeepAliveFetchAdapter
|
|
42
|
-
│ └── ...
|
|
43
|
-
├── types/
|
|
44
|
-
│ ├── events.ts # EventType, EventLevel, MonitorEvent
|
|
45
|
-
│ └── config.ts # MonitorConfig, ServerMonitorConfig
|
|
46
|
-
├── client/
|
|
47
|
-
│ ├── index.ts # FrontendMonitor, monitoredFetch, getSessionId
|
|
48
|
-
│ ├── capture/
|
|
49
|
-
│ │ ├── js-errors.ts # window.onerror + unhandledrejection
|
|
50
|
-
│ │ ├── console.ts # consola reporter / console.* patch
|
|
51
|
-
│ │ ├── network.ts # monitoredFetch wrapper
|
|
52
|
-
│ │ ├── validation.ts # zod-validation-error CustomEvent listener
|
|
53
|
-
│ │ ├── session.ts # UUID session management
|
|
54
|
-
│ │ └── fingerprint.ts # SHA-256 deduplication fingerprint
|
|
55
|
-
│ ├── store/
|
|
56
|
-
│ │ └── index.ts # zustand vanilla event buffer
|
|
57
|
-
│ └── transport/
|
|
58
|
-
│ └── ingest.ts # sendBatch via monitorApi / KeepAliveFetchAdapter
|
|
59
|
-
├── server/
|
|
60
|
-
│ └── index.ts # serverMonitor singleton
|
|
61
|
-
└── index.ts # Types-only re-export
|
|
62
|
-
```
|
|
13
|
+
| Entry | Use |
|
|
14
|
+
|-------|-----|
|
|
15
|
+
| `@djangocfg/monitor` | Types only — server-safe |
|
|
16
|
+
| `@djangocfg/monitor/client` | Browser SDK (`'use client'`) |
|
|
17
|
+
| `@djangocfg/monitor/server` | Node.js / Edge Runtime |
|
|
63
18
|
|
|
64
|
-
##
|
|
19
|
+
## Client (React / Next.js)
|
|
65
20
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
- **Normal flush** → `monitorApi.monitor.ingestCreate(batch)` (standard `FetchAdapter`)
|
|
69
|
-
- **Page unload flush** → separate `monitorApiBeacon` instance with `KeepAliveFetchAdapter` — sets `keepalive: true` on every request, so the browser completes delivery even after navigation
|
|
70
|
-
|
|
71
|
-
**Automatic error collection** (no extra setup after `FrontendMonitor.init()`):
|
|
72
|
-
|
|
73
|
-
| Source | Mechanism |
|
|
74
|
-
|--------|-----------|
|
|
75
|
-
| JS exceptions | `window.onerror` + `unhandledrejection` |
|
|
76
|
-
| Console warnings/errors | consola reporter or `console.*` patch |
|
|
77
|
-
| `@djangocfg/api` Zod failures | `zod-validation-error` CustomEvent |
|
|
78
|
-
| Network errors | `monitoredFetch` wrapper |
|
|
79
|
-
| Server exceptions | `serverMonitor.captureError()` |
|
|
80
|
-
|
|
81
|
-
## Client Usage (React / Next.js)
|
|
82
|
-
|
|
83
|
-
### MonitorProvider
|
|
84
|
-
|
|
85
|
-
```tsx
|
|
86
|
-
// components/MonitorProvider.tsx
|
|
87
|
-
'use client'
|
|
88
|
-
|
|
89
|
-
import { useEffect } from 'react'
|
|
90
|
-
import { FrontendMonitor } from '@djangocfg/monitor/client'
|
|
91
|
-
|
|
92
|
-
export function MonitorProvider() {
|
|
93
|
-
useEffect(() => {
|
|
94
|
-
FrontendMonitor.init({
|
|
95
|
-
project: process.env.NEXT_PUBLIC_PROJECT_NAME ?? 'my-app',
|
|
96
|
-
environment: process.env.NODE_ENV,
|
|
97
|
-
// baseUrl: 'https://api.myapp.com', // default: same origin
|
|
98
|
-
// flushInterval: 5000, // default: 5s
|
|
99
|
-
// captureJsErrors: true, // default: true
|
|
100
|
-
// captureConsole: true, // default: true
|
|
101
|
-
// debug: false,
|
|
102
|
-
})
|
|
103
|
-
return () => FrontendMonitor.destroy()
|
|
104
|
-
}, [])
|
|
105
|
-
|
|
106
|
-
return null
|
|
107
|
-
}
|
|
108
|
-
```
|
|
21
|
+
Drop `MonitorProvider` into your root layout — that's all:
|
|
109
22
|
|
|
110
23
|
```tsx
|
|
111
24
|
// app/layout.tsx
|
|
112
|
-
import { MonitorProvider } from '
|
|
25
|
+
import { MonitorProvider } from '@djangocfg/monitor/client'
|
|
113
26
|
|
|
114
27
|
export default function RootLayout({ children }) {
|
|
115
28
|
return (
|
|
116
|
-
<html
|
|
29
|
+
<html>
|
|
117
30
|
<body>
|
|
118
|
-
<MonitorProvider />
|
|
31
|
+
<MonitorProvider project="my-app" environment={process.env.NODE_ENV} />
|
|
119
32
|
{children}
|
|
120
33
|
</body>
|
|
121
34
|
</html>
|
|
@@ -123,18 +36,18 @@ export default function RootLayout({ children }) {
|
|
|
123
36
|
}
|
|
124
37
|
```
|
|
125
38
|
|
|
126
|
-
|
|
39
|
+
`MonitorProvider` initialises `FrontendMonitor` on mount and tears it down on unmount.
|
|
127
40
|
|
|
128
|
-
|
|
129
|
-
import { monitoredFetch } from '@djangocfg/monitor/client'
|
|
41
|
+
**What gets captured automatically** (no extra setup):
|
|
130
42
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
43
|
+
| Source | Mechanism |
|
|
44
|
+
|--------|-----------|
|
|
45
|
+
| JS exceptions | `window.onerror` + `unhandledrejection` |
|
|
46
|
+
| Console warnings/errors | consola reporter or `console.*` patch |
|
|
47
|
+
| `@djangocfg/api` Zod failures | `zod-validation-error` CustomEvent |
|
|
48
|
+
| Network errors | `monitoredFetch` wrapper |
|
|
136
49
|
|
|
137
|
-
### Manual
|
|
50
|
+
### Manual capture
|
|
138
51
|
|
|
139
52
|
```typescript
|
|
140
53
|
import { FrontendMonitor } from '@djangocfg/monitor/client'
|
|
@@ -149,40 +62,41 @@ FrontendMonitor.capture({
|
|
|
149
62
|
})
|
|
150
63
|
```
|
|
151
64
|
|
|
152
|
-
###
|
|
65
|
+
### Network wrapper
|
|
153
66
|
|
|
154
67
|
```typescript
|
|
155
|
-
import {
|
|
68
|
+
import { monitoredFetch } from '@djangocfg/monitor/client'
|
|
156
69
|
|
|
157
|
-
const
|
|
70
|
+
const res = await monitoredFetch('/api/orders', { method: 'POST', body: JSON.stringify(order) })
|
|
158
71
|
```
|
|
159
72
|
|
|
160
|
-
|
|
73
|
+
### Config options
|
|
161
74
|
|
|
162
|
-
|
|
75
|
+
| Option | Type | Default | Description |
|
|
76
|
+
|--------|------|---------|-------------|
|
|
77
|
+
| `project` | `string` | `''` | Project name sent with every event |
|
|
78
|
+
| `environment` | `string` | `''` | `production` / `staging` / `development` |
|
|
79
|
+
| `baseUrl` | `string` | same origin | Base URL of the django-cfg backend |
|
|
80
|
+
| `flushInterval` | `number` | `5000` | Buffer flush interval (ms) |
|
|
81
|
+
| `maxBufferSize` | `number` | `20` | Max events before immediate flush |
|
|
82
|
+
| `captureJsErrors` | `boolean` | `true` | Capture `window.onerror` + unhandled rejections |
|
|
83
|
+
| `captureConsole` | `boolean` | `true` | Intercept `console.warn` / `console.error` |
|
|
84
|
+
| `debug` | `boolean` | `false` | Log init info to console |
|
|
85
|
+
|
|
86
|
+
## Server (Next.js Route Handlers)
|
|
163
87
|
|
|
164
88
|
```typescript
|
|
165
89
|
// lib/monitor.ts
|
|
166
90
|
import { serverMonitor } from '@djangocfg/monitor/server'
|
|
167
|
-
|
|
168
|
-
serverMonitor.configure({
|
|
169
|
-
project: process.env.PROJECT_NAME ?? 'my-app',
|
|
170
|
-
environment: process.env.NODE_ENV,
|
|
171
|
-
// baseUrl: 'https://api.myapp.com', // required if backend is on different origin
|
|
172
|
-
})
|
|
173
|
-
|
|
91
|
+
serverMonitor.configure({ project: 'my-app', environment: process.env.NODE_ENV })
|
|
174
92
|
export { serverMonitor }
|
|
175
|
-
```
|
|
176
93
|
|
|
177
|
-
### Route Handler
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
94
|
// app/api/orders/route.ts
|
|
181
95
|
import { serverMonitor } from '@/lib/monitor'
|
|
182
96
|
|
|
183
97
|
export async function POST(req: Request) {
|
|
184
98
|
try {
|
|
185
|
-
// ...
|
|
99
|
+
// ...
|
|
186
100
|
} catch (err) {
|
|
187
101
|
await serverMonitor.captureError(err, { url: req.url })
|
|
188
102
|
return new Response('Internal Server Error', { status: 500 })
|
|
@@ -190,152 +104,60 @@ export async function POST(req: Request) {
|
|
|
190
104
|
}
|
|
191
105
|
```
|
|
192
106
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
const response = await fetch(upstreamUrl)
|
|
197
|
-
if (!response.ok) {
|
|
198
|
-
await serverMonitor.captureNetworkError(
|
|
199
|
-
response.status,
|
|
200
|
-
'GET',
|
|
201
|
-
upstreamUrl,
|
|
202
|
-
{ pageUrl: req.url },
|
|
203
|
-
)
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Arbitrary Event
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
import { EventType, EventLevel } from '@djangocfg/monitor/server'
|
|
211
|
-
|
|
212
|
-
await serverMonitor.capture({
|
|
213
|
-
event_type: EventType.WARNING,
|
|
214
|
-
level: EventLevel.WARN,
|
|
215
|
-
message: 'Rate limit approaching',
|
|
216
|
-
url: req.url,
|
|
217
|
-
extra: { remaining: 5 },
|
|
218
|
-
})
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
## Types
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
import type { MonitorConfig, MonitorEvent } from '@djangocfg/monitor'
|
|
225
|
-
import { EventType, EventLevel } from '@djangocfg/monitor'
|
|
226
|
-
|
|
227
|
-
EventType.JS_ERROR // 'js_error'
|
|
228
|
-
EventType.NETWORK_ERROR // 'network_error'
|
|
229
|
-
EventType.WARNING // 'warning'
|
|
230
|
-
EventType.ERROR // 'error'
|
|
231
|
-
EventType.INFO // 'info'
|
|
232
|
-
|
|
233
|
-
EventLevel.ERROR // 'error'
|
|
234
|
-
EventLevel.WARN // 'warn'
|
|
235
|
-
EventLevel.INFO // 'info'
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### MonitorConfig
|
|
239
|
-
|
|
240
|
-
| Option | Type | Default | Description |
|
|
241
|
-
|--------|------|---------|-------------|
|
|
242
|
-
| `project` | `string` | `''` | Project name sent with every event |
|
|
243
|
-
| `environment` | `string` | `''` | `production` / `staging` / `development` |
|
|
244
|
-
| `baseUrl` | `string` | `''` | Base URL of the django-cfg backend (same origin by default) |
|
|
245
|
-
| `flushInterval` | `number` | `5000` | Buffer flush interval (ms) |
|
|
246
|
-
| `maxBufferSize` | `number` | `20` | Max events before immediate flush |
|
|
247
|
-
| `captureJsErrors` | `boolean` | `true` | Capture `window.onerror` + unhandled rejections |
|
|
248
|
-
| `captureConsole` | `boolean` | `true` | Intercept `console.warn` / `console.error` |
|
|
249
|
-
| `debug` | `boolean` | `false` | Log init info to console |
|
|
250
|
-
|
|
251
|
-
### ServerMonitorConfig
|
|
252
|
-
|
|
253
|
-
| Option | Type | Default | Description |
|
|
254
|
-
|--------|------|---------|-------------|
|
|
255
|
-
| `project` | `string` | `''` | Project name |
|
|
256
|
-
| `environment` | `string` | `''` | Environment name |
|
|
257
|
-
| `baseUrl` | `string` | `''` | Base URL of the django-cfg backend (absolute required on server) |
|
|
258
|
-
|
|
259
|
-
## Zod Validation Integration
|
|
260
|
-
|
|
261
|
-
`@djangocfg/api` automatically dispatches a `zod-validation-error` CustomEvent whenever a response fails schema validation. `@djangocfg/monitor/client` listens and forwards it as a `WARNING` — zero setup needed.
|
|
262
|
-
|
|
263
|
-
```
|
|
264
|
-
@djangocfg/api fetcher validates response with Zod
|
|
265
|
-
→ dispatches window CustomEvent('zod-validation-error', { detail })
|
|
266
|
-
→ @djangocfg/monitor/client capture/validation.ts catches it
|
|
267
|
-
→ pushed to store → flushed to backend
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
## Custom HTTP Adapter
|
|
271
|
-
|
|
272
|
-
The generated `KeepAliveFetchAdapter` is also available if you need it elsewhere:
|
|
107
|
+
Or use the `withMonitor` HOC from `@djangocfg/nextjs/monitor`:
|
|
273
108
|
|
|
274
109
|
```typescript
|
|
275
|
-
import {
|
|
276
|
-
// or directly from generated:
|
|
277
|
-
import { API, KeepAliveFetchAdapter } from '@djangocfg/monitor/client'
|
|
110
|
+
import { withMonitor } from '@djangocfg/nextjs/monitor'
|
|
278
111
|
|
|
279
|
-
const
|
|
280
|
-
|
|
112
|
+
export const POST = withMonitor(async (req) => {
|
|
113
|
+
// errors are captured automatically
|
|
281
114
|
})
|
|
282
115
|
```
|
|
283
116
|
|
|
284
117
|
## Django Backend
|
|
285
118
|
|
|
286
|
-
Enable the `cfg_monitor` extension:
|
|
287
|
-
|
|
288
119
|
```python
|
|
289
120
|
# cfg.py
|
|
290
|
-
from django_cfg import DjangoConfig
|
|
291
|
-
|
|
292
121
|
class Config(DjangoConfig):
|
|
293
|
-
installed_apps = [
|
|
294
|
-
...
|
|
295
|
-
'django_cfg.apps.system.monitor',
|
|
296
|
-
]
|
|
122
|
+
installed_apps = [..., 'django_cfg.apps.system.monitor']
|
|
297
123
|
```
|
|
298
124
|
|
|
299
|
-
|
|
300
|
-
|---|---|
|
|
301
|
-
| Endpoint | `POST /cfg/monitor/ingest/` |
|
|
302
|
-
| Auth | not required |
|
|
303
|
-
| Rate limit | 100 req/min per IP |
|
|
304
|
-
| Batch size | up to 50 events |
|
|
125
|
+
Ingest endpoint: `POST /cfg/monitor/ingest/` — no auth required, 100 req/min per IP.
|
|
305
126
|
|
|
306
|
-
##
|
|
127
|
+
## Browser Console Testing
|
|
307
128
|
|
|
308
|
-
|
|
309
|
-
# Regenerate API client from Django OpenAPI schema
|
|
310
|
-
make generate
|
|
129
|
+
After `MonitorProvider` mounts, `window.monitor` is available in DevTools for manual testing:
|
|
311
130
|
|
|
312
|
-
|
|
313
|
-
|
|
131
|
+
```javascript
|
|
132
|
+
// Fire events from DevTools console
|
|
133
|
+
window.monitor.error('Payment failed', { orderId: '123' })
|
|
134
|
+
window.monitor.warn('Slow response', { ms: 2400 })
|
|
135
|
+
window.monitor.info('User action', { action: 'checkout' })
|
|
136
|
+
window.monitor.network(404, 'GET', '/api/users/')
|
|
137
|
+
window.monitor.network(502, 'POST', '/api/orders/', { retries: 3 })
|
|
314
138
|
|
|
315
|
-
|
|
316
|
-
|
|
139
|
+
// Force-send buffered events immediately
|
|
140
|
+
window.monitor.flush()
|
|
317
141
|
|
|
318
|
-
|
|
319
|
-
|
|
142
|
+
// Inspect current state
|
|
143
|
+
window.monitor.status()
|
|
144
|
+
// → logs config, buffer size, session_id
|
|
320
145
|
```
|
|
321
146
|
|
|
322
|
-
##
|
|
147
|
+
## Debug Panel Integration
|
|
323
148
|
|
|
324
|
-
|
|
325
|
-
|---------|----------|-------------|
|
|
326
|
-
| `consola` | optional | Uses consola reporter instead of patching `console.*` |
|
|
327
|
-
| `zustand` | optional | Required for the client entry point event buffer |
|
|
149
|
+
Install `@djangocfg/debuger` alongside this package — it auto-bridges the monitor event store into the debug panel's Logs tab. No extra setup needed.
|
|
328
150
|
|
|
329
|
-
|
|
151
|
+
```bash
|
|
152
|
+
pnpm add @djangocfg/debuger
|
|
153
|
+
```
|
|
330
154
|
|
|
331
|
-
|
|
332
|
-
- Django with `django_cfg >= 1.7` and `monitor` extension
|
|
155
|
+
Events captured by monitor (JS errors, console, network) appear in the panel as `monitor:JS_ERROR`, `monitor:NETWORK_ERROR`, etc.
|
|
333
156
|
|
|
334
|
-
##
|
|
157
|
+
## Safety
|
|
335
158
|
|
|
336
|
-
|
|
159
|
+
Transport errors are **always swallowed** — monitor never crashes your app and never sends its own errors to itself. If the backend is unreachable, events are silently dropped.
|
|
337
160
|
|
|
338
|
-
##
|
|
161
|
+
## License
|
|
339
162
|
|
|
340
|
-
|
|
341
|
-
- [GitHub](https://github.com/markolofsen/django-cfg)
|
|
163
|
+
MIT
|