@djangocfg/monitor 2.1.226 → 2.1.228

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.
Files changed (36) hide show
  1. package/README.md +2 -6
  2. package/dist/client.cjs +48 -26
  3. package/dist/client.cjs.map +1 -1
  4. package/dist/client.d.cts +31 -33
  5. package/dist/client.d.ts +31 -33
  6. package/dist/client.mjs +48 -26
  7. package/dist/client.mjs.map +1 -1
  8. package/dist/index.cjs +9 -10
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +29 -33
  11. package/dist/index.d.ts +29 -33
  12. package/dist/index.mjs +9 -10
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/server.cjs +10 -11
  15. package/dist/server.cjs.map +1 -1
  16. package/dist/server.d.cts +29 -33
  17. package/dist/server.d.ts +29 -33
  18. package/dist/server.mjs +10 -11
  19. package/dist/server.mjs.map +1 -1
  20. package/package.json +2 -2
  21. package/src/_api/generated/cfg_monitor/_utils/schemas/FrontendEventIngestRequest.schema.ts +5 -6
  22. package/src/_api/generated/cfg_monitor/_utils/schemas/IngestBatchRequest.schema.ts +2 -2
  23. package/src/_api/generated/cfg_monitor/enums.ts +14 -16
  24. package/src/_api/generated/cfg_monitor/monitor/client.ts +2 -1
  25. package/src/_api/generated/cfg_monitor/monitor/models.ts +16 -18
  26. package/src/_api/generated/cfg_monitor/schema.json +19 -27
  27. package/src/client/capture/console.ts +3 -1
  28. package/src/client/capture/js-errors.ts +7 -0
  29. package/src/client/capture/network.ts +1 -1
  30. package/src/client/capture/validation.ts +1 -1
  31. package/src/client/constants.ts +7 -0
  32. package/src/client/index.ts +2 -1
  33. package/src/client/store/index.ts +28 -2
  34. package/src/client/transport/ingest.ts +5 -9
  35. package/src/client/window.ts +3 -3
  36. package/src/server/index.ts +1 -1
package/README.md CHANGED
@@ -116,13 +116,9 @@ export const POST = withMonitor(async (req) => {
116
116
 
117
117
  ## Django Backend
118
118
 
119
- ```python
120
- # cfg.py
121
- class Config(DjangoConfig):
122
- installed_apps = [..., 'django_cfg.apps.system.monitor']
123
- ```
119
+ The monitor module is included automatically with `django-cfg` — no extra `installed_apps` entry needed.
124
120
 
125
- Ingest endpoint: `POST /cfg/monitor/ingest/` — no auth required, 100 req/min per IP.
121
+ Ingest endpoint: `POST /cfg/monitor/ingest/` — no auth required, always mounted.
126
122
 
127
123
  ## Browser Console Testing
128
124
 
package/dist/client.cjs CHANGED
@@ -263,6 +263,8 @@ var require_retry2 = __commonJS({
263
263
  // src/client/index.ts
264
264
  var client_exports = {};
265
265
  __export(client_exports, {
266
+ EventLevel: () => FrontendEventIngestRequestLevel,
267
+ EventType: () => FrontendEventIngestRequestEventType,
266
268
  FrontendMonitor: () => FrontendMonitor,
267
269
  MonitorProvider: () => MonitorProvider,
268
270
  getSessionId: () => getSessionId,
@@ -342,7 +344,8 @@ var _Monitor = class _Monitor {
342
344
  /**
343
345
  * Ingest browser events
344
346
  *
345
- * Accepts a batch of up to 50 frontend events. No authentication required.
347
+ * Accepts a batch of up to 50 frontend events. No authentication required
348
+ * — anonymous visitors can send events.
346
349
  */
347
350
  async ingestCreate(data) {
348
351
  const response = await this.client.request("POST", "/cfg/monitor/ingest/", { body: data });
@@ -1120,19 +1123,18 @@ var MemoryStorageAdapter = _MemoryStorageAdapter;
1120
1123
 
1121
1124
  // src/_api/generated/cfg_monitor/enums.ts
1122
1125
  var FrontendEventIngestRequestEventType = /* @__PURE__ */ ((FrontendEventIngestRequestEventType2) => {
1126
+ FrontendEventIngestRequestEventType2["JS_ERROR"] = "JS_ERROR";
1127
+ FrontendEventIngestRequestEventType2["NETWORK_ERROR"] = "NETWORK_ERROR";
1123
1128
  FrontendEventIngestRequestEventType2["ERROR"] = "ERROR";
1124
1129
  FrontendEventIngestRequestEventType2["WARNING"] = "WARNING";
1125
- FrontendEventIngestRequestEventType2["INFO"] = "INFO";
1126
1130
  FrontendEventIngestRequestEventType2["PAGE_VIEW"] = "PAGE_VIEW";
1127
1131
  FrontendEventIngestRequestEventType2["PERFORMANCE"] = "PERFORMANCE";
1128
- FrontendEventIngestRequestEventType2["NETWORK_ERROR"] = "NETWORK_ERROR";
1129
- FrontendEventIngestRequestEventType2["JS_ERROR"] = "JS_ERROR";
1130
1132
  FrontendEventIngestRequestEventType2["CONSOLE"] = "CONSOLE";
1131
1133
  return FrontendEventIngestRequestEventType2;
1132
1134
  })(FrontendEventIngestRequestEventType || {});
1133
1135
  var FrontendEventIngestRequestLevel = /* @__PURE__ */ ((FrontendEventIngestRequestLevel2) => {
1134
1136
  FrontendEventIngestRequestLevel2["ERROR"] = "error";
1135
- FrontendEventIngestRequestLevel2["WARN"] = "warn";
1137
+ FrontendEventIngestRequestLevel2["WARNING"] = "warning";
1136
1138
  FrontendEventIngestRequestLevel2["INFO"] = "info";
1137
1139
  FrontendEventIngestRequestLevel2["DEBUG"] = "debug";
1138
1140
  return FrontendEventIngestRequestLevel2;
@@ -1150,13 +1152,12 @@ var FrontendEventIngestRequestSchema = import_zod.z.object({
1150
1152
  http_status: import_zod.z.number().int().nullable().optional(),
1151
1153
  http_method: import_zod.z.string().max(10).optional(),
1152
1154
  http_url: import_zod.z.string().max(2e3).optional(),
1155
+ session_id: import_zod.z.string().max(64).optional(),
1153
1156
  user_agent: import_zod.z.string().max(500).optional(),
1154
- session_id: import_zod.z.string().regex(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i).nullable().optional(),
1155
- browser_fingerprint: import_zod.z.string().max(64).optional(),
1156
- extra: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
1157
- project_name: import_zod.z.string().max(100).optional(),
1157
+ build_id: import_zod.z.string().max(100).optional(),
1158
1158
  environment: import_zod.z.string().max(20).optional(),
1159
- build_id: import_zod.z.string().max(100).optional()
1159
+ extra: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
1160
+ project_name: import_zod.z.string().max(100).optional()
1160
1161
  });
1161
1162
 
1162
1163
  // src/_api/generated/cfg_monitor/_utils/schemas/IngestBatchRequest.schema.ts
@@ -1343,23 +1344,24 @@ function syncBeaconBaseUrl() {
1343
1344
  __name(syncBeaconBaseUrl, "syncBeaconBaseUrl");
1344
1345
  async function sendBatch(batch, useBeacon = false) {
1345
1346
  if (batch.events.length === 0) return;
1346
- try {
1347
- if (useBeacon) {
1348
- syncBeaconBaseUrl();
1349
- await monitorApiBeacon.monitor.ingestCreate(batch);
1350
- } else {
1351
- await monitorApi.monitor.ingestCreate(batch);
1352
- }
1353
- } catch {
1347
+ if (useBeacon) {
1348
+ syncBeaconBaseUrl();
1349
+ await monitorApiBeacon.monitor.ingestCreate(batch);
1350
+ } else {
1351
+ await monitorApi.monitor.ingestCreate(batch);
1354
1352
  }
1355
1353
  }
1356
1354
  __name(sendBatch, "sendBatch");
1357
1355
 
1358
1356
  // src/client/store/index.ts
1357
+ var CIRCUIT_BREAKER_THRESHOLD = 3;
1358
+ var CIRCUIT_BREAKER_COOLDOWN_MS = 6e4;
1359
1359
  var monitorStore = (0, import_vanilla.createStore)((set, get) => ({
1360
1360
  config: {},
1361
1361
  buffer: [],
1362
1362
  initialized: false,
1363
+ _consecutiveFailures: 0,
1364
+ _pausedUntil: 0,
1363
1365
  push(event) {
1364
1366
  const { config, buffer } = get();
1365
1367
  const maxSize = config.maxBufferSize ?? 20;
@@ -1385,23 +1387,40 @@ var monitorStore = (0, import_vanilla.createStore)((set, get) => ({
1385
1387
  }
1386
1388
  },
1387
1389
  flush(useBeacon = false) {
1388
- const { buffer } = get();
1390
+ const { buffer, _pausedUntil } = get();
1389
1391
  if (buffer.length === 0) return;
1392
+ if (Date.now() < _pausedUntil) return;
1390
1393
  const batch = buffer.slice(0, 50);
1391
1394
  set({ buffer: buffer.slice(50) });
1392
- sendBatch({ events: batch }, useBeacon);
1395
+ sendBatch({ events: batch }, useBeacon).then(
1396
+ () => {
1397
+ set({ _consecutiveFailures: 0, _pausedUntil: 0 });
1398
+ },
1399
+ () => {
1400
+ const failures = get()._consecutiveFailures + 1;
1401
+ const pausedUntil = failures >= CIRCUIT_BREAKER_THRESHOLD ? Date.now() + CIRCUIT_BREAKER_COOLDOWN_MS : get()._pausedUntil;
1402
+ set({ _consecutiveFailures: failures, _pausedUntil: pausedUntil });
1403
+ }
1404
+ );
1393
1405
  },
1394
1406
  setConfig(config) {
1395
1407
  set({ config, initialized: true });
1396
1408
  }
1397
1409
  }));
1398
1410
 
1411
+ // src/client/constants.ts
1412
+ var MONITOR_INGEST_PATTERN = /cfg\/monitor\/ingest/;
1413
+
1399
1414
  // src/client/capture/js-errors.ts
1400
1415
  var MSG_MAX = 2e3;
1401
1416
  function truncate(s, max = MSG_MAX) {
1402
1417
  return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
1403
1418
  }
1404
1419
  __name(truncate, "truncate");
1420
+ function isMonitorOwnError(msg, stack) {
1421
+ return MONITOR_INGEST_PATTERN.test(msg) || MONITOR_INGEST_PATTERN.test(stack ?? "");
1422
+ }
1423
+ __name(isMonitorOwnError, "isMonitorOwnError");
1405
1424
  var HYDRATION_NOISE = [
1406
1425
  /hydration failed/i,
1407
1426
  /there was an error while hydrating/i,
@@ -1436,6 +1455,7 @@ function installJsErrorCapture() {
1436
1455
  const msg = truncate(typeof message === "string" ? message : String(message));
1437
1456
  if (isHydrationNoise(msg)) return;
1438
1457
  const stack = error?.stack ?? `at ${source}:${lineno}:${colno}`;
1458
+ if (isMonitorOwnError(msg, stack)) return;
1439
1459
  const url = window.location.href;
1440
1460
  const fingerprint = await computeFingerprint(msg, stack, url);
1441
1461
  if (isRecentlySent(fingerprint)) return;
@@ -1462,6 +1482,7 @@ function installJsErrorCapture() {
1462
1482
  const msg = truncate(reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "Unhandled promise rejection");
1463
1483
  if (isHydrationNoise(msg)) return;
1464
1484
  const stack = reason instanceof Error ? reason.stack ?? "" : "";
1485
+ if (isMonitorOwnError(msg, stack)) return;
1465
1486
  const url = window.location.href;
1466
1487
  const fingerprint = await computeFingerprint(msg, stack, url);
1467
1488
  if (isRecentlySent(fingerprint)) return;
@@ -1494,7 +1515,7 @@ __name(installJsErrorCapture, "installJsErrorCapture");
1494
1515
 
1495
1516
  // src/client/capture/console.ts
1496
1517
  var levelMap = {
1497
- warn: "warn" /* WARN */,
1518
+ warn: "warning" /* WARNING */,
1498
1519
  error: "error" /* ERROR */
1499
1520
  };
1500
1521
  var typeMap = {
@@ -1523,6 +1544,7 @@ __name(stringify, "stringify");
1523
1544
  async function captureConsoleEvent(level, args) {
1524
1545
  try {
1525
1546
  const message = stringify(args);
1547
+ if (MONITOR_INGEST_PATTERN.test(message)) return;
1526
1548
  const url = typeof window !== "undefined" ? window.location.href : "";
1527
1549
  const fingerprint = await computeFingerprint(message, "", url);
1528
1550
  const { config } = monitorStore.getState();
@@ -1588,7 +1610,7 @@ function installValidationCapture() {
1588
1610
  const rawMsg = `Zod validation error in ${detail.operation}: ${detail.error?.message ?? "unknown"}`;
1589
1611
  monitorStore.getState().push({
1590
1612
  event_type: "WARNING" /* WARNING */,
1591
- level: "warn" /* WARN */,
1613
+ level: "warning" /* WARNING */,
1592
1614
  message: rawMsg.length > 500 ? rawMsg.slice(0, 499) + "\u2026" : rawMsg,
1593
1615
  url: window.location.href,
1594
1616
  http_method: detail.method,
@@ -1617,7 +1639,7 @@ async function monitoredFetch(input, init) {
1617
1639
  const { config } = monitorStore.getState();
1618
1640
  monitorStore.getState().push({
1619
1641
  event_type: "NETWORK_ERROR" /* NETWORK_ERROR */,
1620
- level: response.status >= 500 ? "error" /* ERROR */ : "warn" /* WARN */,
1642
+ level: response.status >= 500 ? "error" /* ERROR */ : "warning" /* WARNING */,
1621
1643
  message: `HTTP ${response.status} ${response.statusText} \u2014 ${method} ${url}`,
1622
1644
  url: typeof window !== "undefined" ? window.location.href : "",
1623
1645
  http_status: response.status,
@@ -1677,17 +1699,17 @@ function initWindowMonitor() {
1677
1699
  console.log("[monitor] error captured \u2192", message);
1678
1700
  },
1679
1701
  warn(message, extra) {
1680
- monitorStore.getState().push(makeEvent("WARNING" /* WARNING */, "warn" /* WARN */, message, extra));
1702
+ monitorStore.getState().push(makeEvent("WARNING" /* WARNING */, "warning" /* WARNING */, message, extra));
1681
1703
  console.log("[monitor] warn captured \u2192", message);
1682
1704
  },
1683
1705
  info(message, extra) {
1684
- monitorStore.getState().push(makeEvent("INFO" /* INFO */, "info" /* INFO */, message, extra));
1706
+ monitorStore.getState().push(makeEvent("WARNING" /* WARNING */, "info" /* INFO */, message, extra));
1685
1707
  console.log("[monitor] info captured \u2192", message);
1686
1708
  },
1687
1709
  network(status, method, url, extra) {
1688
1710
  const event = makeEvent(
1689
1711
  "NETWORK_ERROR" /* NETWORK_ERROR */,
1690
- status >= 500 ? "error" /* ERROR */ : "warn" /* WARN */,
1712
+ status >= 500 ? "error" /* ERROR */ : "warning" /* WARNING */,
1691
1713
  `${method} ${url} \u2192 ${status}`,
1692
1714
  extra
1693
1715
  );