@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 CHANGED
@@ -1,8 +1,6 @@
1
1
  # @djangocfg/monitor
2
2
 
3
- Browser error and event monitoring SDK for django-cfg backends.
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 | Import | Description |
27
- |-------|--------|-------------|
28
- | **Main** | `@djangocfg/monitor` | Types only, server-safe |
29
- | **Client** | `@djangocfg/monitor/client` | Browser SDK (`"use client"`) |
30
- | **Server** | `@djangocfg/monitor/server` | Node.js / Edge Runtime |
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
- ## How It Works
19
+ ## Client (React / Next.js)
65
20
 
66
- All transport uses the **generated API client** (`monitorApi`) no hardcoded URLs or raw `fetch` calls.
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 '@/components/MonitorProvider'
25
+ import { MonitorProvider } from '@djangocfg/monitor/client'
113
26
 
114
27
  export default function RootLayout({ children }) {
115
28
  return (
116
- <html lang="en">
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
- ### Network Monitoring
39
+ `MonitorProvider` initialises `FrontendMonitor` on mount and tears it down on unmount.
127
40
 
128
- ```typescript
129
- import { monitoredFetch } from '@djangocfg/monitor/client'
41
+ **What gets captured automatically** (no extra setup):
130
42
 
131
- const response = await monitoredFetch('/api/orders', {
132
- method: 'POST',
133
- body: JSON.stringify(order),
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 Event Capture
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
- ### Session ID
65
+ ### Network wrapper
153
66
 
154
67
  ```typescript
155
- import { getSessionId } from '@djangocfg/monitor/client'
68
+ import { monitoredFetch } from '@djangocfg/monitor/client'
156
69
 
157
- const sessionId = getSessionId() // UUID stored in localStorage + cookie
70
+ const res = await monitoredFetch('/api/orders', { method: 'POST', body: JSON.stringify(order) })
158
71
  ```
159
72
 
160
- ## Server Usage (Next.js Route Handlers / Server Components)
73
+ ### Config options
161
74
 
162
- ### Configure once
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
- // ... handle request
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
- ### Network Error
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 { KeepAliveFetchAdapter } from '@djangocfg/monitor/client'
276
- // or directly from generated:
277
- import { API, KeepAliveFetchAdapter } from '@djangocfg/monitor/client'
110
+ import { withMonitor } from '@djangocfg/nextjs/monitor'
278
111
 
279
- const api = new API('https://api.myapp.com', {
280
- httpClient: new KeepAliveFetchAdapter(),
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
- ## Development
127
+ ## Browser Console Testing
307
128
 
308
- ```bash
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
- # Build package
313
- make build
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
- # Watch mode
316
- pnpm dev
139
+ // Force-send buffered events immediately
140
+ window.monitor.flush()
317
141
 
318
- # Type check
319
- pnpm check
142
+ // Inspect current state
143
+ window.monitor.status()
144
+ // → logs config, buffer size, session_id
320
145
  ```
321
146
 
322
- ## Peer Dependencies
147
+ ## Debug Panel Integration
323
148
 
324
- | Package | Required | Description |
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
- ## Requirements
151
+ ```bash
152
+ pnpm add @djangocfg/debuger
153
+ ```
330
154
 
331
- - Next.js >= 15 (or any React >= 19 app)
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
- ## License
157
+ ## Safety
335
158
 
336
- MIT
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
- ## Links
161
+ ## License
339
162
 
340
- - [DjangoCFG Documentation](https://djangocfg.com)
341
- - [GitHub](https://github.com/markolofsen/django-cfg)
163
+ MIT