@djangocfg/monitor 2.1.216
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 +341 -0
- package/dist/client.cjs +1273 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +123 -0
- package/dist/client.d.ts +123 -0
- package/dist/client.mjs +1243 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.cjs +18 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +101 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -0
- package/dist/server.cjs +947 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +117 -0
- package/dist/server.d.ts +117 -0
- package/dist/server.mjs +917 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +82 -0
- package/src/.claude/.sidecar/activity.jsonl +1 -0
- package/src/.claude/.sidecar/map_cache.json +38 -0
- package/src/.claude/.sidecar/usage.json +5 -0
- package/src/.claude/project-map.md +29 -0
- package/src/_api/BaseClient.ts +18 -0
- package/src/_api/generated/cfg_monitor/CLAUDE.md +60 -0
- package/src/_api/generated/cfg_monitor/_utils/fetchers/index.ts +30 -0
- package/src/_api/generated/cfg_monitor/_utils/fetchers/monitor.ts +51 -0
- package/src/_api/generated/cfg_monitor/_utils/hooks/index.ts +30 -0
- package/src/_api/generated/cfg_monitor/_utils/hooks/monitor.ts +43 -0
- package/src/_api/generated/cfg_monitor/_utils/schemas/FrontendEventIngestRequest.schema.ts +34 -0
- package/src/_api/generated/cfg_monitor/_utils/schemas/IngestBatchRequest.schema.ts +20 -0
- package/src/_api/generated/cfg_monitor/_utils/schemas/index.ts +22 -0
- package/src/_api/generated/cfg_monitor/api-instance.ts +181 -0
- package/src/_api/generated/cfg_monitor/client.ts +322 -0
- package/src/_api/generated/cfg_monitor/enums.ts +36 -0
- package/src/_api/generated/cfg_monitor/errors.ts +118 -0
- package/src/_api/generated/cfg_monitor/http.ts +137 -0
- package/src/_api/generated/cfg_monitor/index.ts +317 -0
- package/src/_api/generated/cfg_monitor/logger.ts +261 -0
- package/src/_api/generated/cfg_monitor/monitor/client.ts +25 -0
- package/src/_api/generated/cfg_monitor/monitor/index.ts +4 -0
- package/src/_api/generated/cfg_monitor/monitor/models.ts +48 -0
- package/src/_api/generated/cfg_monitor/retry.ts +177 -0
- package/src/_api/generated/cfg_monitor/schema.json +184 -0
- package/src/_api/generated/cfg_monitor/storage.ts +163 -0
- package/src/_api/generated/cfg_monitor/validation-events.ts +135 -0
- package/src/_api/index.ts +6 -0
- package/src/client/capture/console.ts +72 -0
- package/src/client/capture/fingerprint.ts +27 -0
- package/src/client/capture/js-errors.ts +70 -0
- package/src/client/capture/network.ts +47 -0
- package/src/client/capture/session.ts +33 -0
- package/src/client/capture/validation.ts +38 -0
- package/src/client/index.ts +72 -0
- package/src/client/store/index.ts +41 -0
- package/src/client/transport/ingest.ts +31 -0
- package/src/index.ts +12 -0
- package/src/server/index.ts +85 -0
- package/src/types/config.ts +33 -0
- package/src/types/events.ts +5 -0
- package/src/types/index.ts +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# @djangocfg/monitor
|
|
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.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @djangocfg/monitor
|
|
11
|
+
```
|
|
12
|
+
|
|
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
|
+
## Entry Points
|
|
25
|
+
|
|
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
|
+
```
|
|
63
|
+
|
|
64
|
+
## How It Works
|
|
65
|
+
|
|
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
|
+
```
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
// app/layout.tsx
|
|
112
|
+
import { MonitorProvider } from '@/components/MonitorProvider'
|
|
113
|
+
|
|
114
|
+
export default function RootLayout({ children }) {
|
|
115
|
+
return (
|
|
116
|
+
<html lang="en">
|
|
117
|
+
<body>
|
|
118
|
+
<MonitorProvider />
|
|
119
|
+
{children}
|
|
120
|
+
</body>
|
|
121
|
+
</html>
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Network Monitoring
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { monitoredFetch } from '@djangocfg/monitor/client'
|
|
130
|
+
|
|
131
|
+
const response = await monitoredFetch('/api/orders', {
|
|
132
|
+
method: 'POST',
|
|
133
|
+
body: JSON.stringify(order),
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Manual Event Capture
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { FrontendMonitor } from '@djangocfg/monitor/client'
|
|
141
|
+
import { EventType, EventLevel } from '@djangocfg/monitor'
|
|
142
|
+
|
|
143
|
+
FrontendMonitor.capture({
|
|
144
|
+
event_type: EventType.JS_ERROR,
|
|
145
|
+
level: EventLevel.ERROR,
|
|
146
|
+
message: 'Payment failed',
|
|
147
|
+
url: window.location.href,
|
|
148
|
+
extra: { orderId: '123' },
|
|
149
|
+
})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Session ID
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { getSessionId } from '@djangocfg/monitor/client'
|
|
156
|
+
|
|
157
|
+
const sessionId = getSessionId() // UUID stored in localStorage + cookie
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Server Usage (Next.js Route Handlers / Server Components)
|
|
161
|
+
|
|
162
|
+
### Configure once
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// lib/monitor.ts
|
|
166
|
+
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
|
+
|
|
174
|
+
export { serverMonitor }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Route Handler
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// app/api/orders/route.ts
|
|
181
|
+
import { serverMonitor } from '@/lib/monitor'
|
|
182
|
+
|
|
183
|
+
export async function POST(req: Request) {
|
|
184
|
+
try {
|
|
185
|
+
// ... handle request
|
|
186
|
+
} catch (err) {
|
|
187
|
+
await serverMonitor.captureError(err, { url: req.url })
|
|
188
|
+
return new Response('Internal Server Error', { status: 500 })
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
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:
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { KeepAliveFetchAdapter } from '@djangocfg/monitor/client'
|
|
276
|
+
// or directly from generated:
|
|
277
|
+
import { API, KeepAliveFetchAdapter } from '@djangocfg/monitor/client'
|
|
278
|
+
|
|
279
|
+
const api = new API('https://api.myapp.com', {
|
|
280
|
+
httpClient: new KeepAliveFetchAdapter(),
|
|
281
|
+
})
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Django Backend
|
|
285
|
+
|
|
286
|
+
Enable the `cfg_monitor` extension:
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
# cfg.py
|
|
290
|
+
from django_cfg import DjangoConfig
|
|
291
|
+
|
|
292
|
+
class Config(DjangoConfig):
|
|
293
|
+
installed_apps = [
|
|
294
|
+
...
|
|
295
|
+
'django_cfg.apps.system.monitor',
|
|
296
|
+
]
|
|
297
|
+
```
|
|
298
|
+
|
|
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 |
|
|
305
|
+
|
|
306
|
+
## Development
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Regenerate API client from Django OpenAPI schema
|
|
310
|
+
make generate
|
|
311
|
+
|
|
312
|
+
# Build package
|
|
313
|
+
make build
|
|
314
|
+
|
|
315
|
+
# Watch mode
|
|
316
|
+
pnpm dev
|
|
317
|
+
|
|
318
|
+
# Type check
|
|
319
|
+
pnpm check
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Peer Dependencies
|
|
323
|
+
|
|
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 |
|
|
328
|
+
|
|
329
|
+
## Requirements
|
|
330
|
+
|
|
331
|
+
- Next.js >= 15 (or any React >= 19 app)
|
|
332
|
+
- Django with `django_cfg >= 1.7` and `monitor` extension
|
|
333
|
+
|
|
334
|
+
## License
|
|
335
|
+
|
|
336
|
+
MIT
|
|
337
|
+
|
|
338
|
+
## Links
|
|
339
|
+
|
|
340
|
+
- [DjangoCFG Documentation](https://djangocfg.com)
|
|
341
|
+
- [GitHub](https://github.com/markolofsen/django-cfg)
|