@djangocfg/monitor 2.1.237 → 2.1.239

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/dist/client.d.cts CHANGED
@@ -88,6 +88,10 @@ interface MonitorConfig {
88
88
  captureJsErrors?: boolean;
89
89
  /** Log debug info to console. Default: false */
90
90
  debug?: boolean;
91
+ /** Deduplication TTL in ms for per-capture-source filtering. Default: 5000 */
92
+ dedupeTtl?: number;
93
+ /** Deduplication TTL in ms for the global store-level filter (cross-source). Default: 30000 */
94
+ dedupeStoreTtl?: number;
91
95
  }
92
96
 
93
97
  declare function monitoredFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
package/dist/client.d.ts CHANGED
@@ -88,6 +88,10 @@ interface MonitorConfig {
88
88
  captureJsErrors?: boolean;
89
89
  /** Log debug info to console. Default: false */
90
90
  debug?: boolean;
91
+ /** Deduplication TTL in ms for per-capture-source filtering. Default: 5000 */
92
+ dedupeTtl?: number;
93
+ /** Deduplication TTL in ms for the global store-level filter (cross-source). Default: 30000 */
94
+ dedupeStoreTtl?: number;
91
95
  }
92
96
 
93
97
  declare function monitoredFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
package/dist/client.mjs CHANGED
@@ -1341,11 +1341,36 @@ __name(sendBatch, "sendBatch");
1341
1341
  // src/client/utils/env.ts
1342
1342
  var isDevelopment = process.env.NODE_ENV === "development";
1343
1343
  var isProduction = !isDevelopment;
1344
- var MONITOR_VERSION = "2.1.237";
1344
+ var MONITOR_VERSION = "2.1.239";
1345
+
1346
+ // src/client/constants.ts
1347
+ var MONITOR_INGEST_PATTERN = /cfg\/monitor\/ingest/;
1348
+ var DEFAULT_DEDUPE_TTL = 5e3;
1349
+ var DEFAULT_DEDUPE_STORE_TTL = 3e4;
1345
1350
 
1346
1351
  // src/client/store/index.ts
1347
1352
  var CIRCUIT_BREAKER_THRESHOLD = 3;
1348
1353
  var CIRCUIT_BREAKER_COOLDOWN_MS = 6e4;
1354
+ var STORE_DEDUP_MAX = 200;
1355
+ var _recentPushKeys = /* @__PURE__ */ new Map();
1356
+ function _pushDedupeKey(event) {
1357
+ const msg = (event.message ?? "").slice(0, 100);
1358
+ return `${event.event_type}:${event.level}:${msg}:${event.http_url ?? event.url ?? ""}`;
1359
+ }
1360
+ __name(_pushDedupeKey, "_pushDedupeKey");
1361
+ function _isRecentPush(key, ttl) {
1362
+ const now = Date.now();
1363
+ const last = _recentPushKeys.get(key);
1364
+ if (last !== void 0 && now - last < ttl) return true;
1365
+ _recentPushKeys.set(key, now);
1366
+ if (_recentPushKeys.size > STORE_DEDUP_MAX) {
1367
+ for (const [k, ts] of _recentPushKeys) {
1368
+ if (now - ts > ttl) _recentPushKeys.delete(k);
1369
+ }
1370
+ }
1371
+ return false;
1372
+ }
1373
+ __name(_isRecentPush, "_isRecentPush");
1349
1374
  var monitorStore = createStore((set, get) => ({
1350
1375
  config: {},
1351
1376
  buffer: [],
@@ -1354,6 +1379,9 @@ var monitorStore = createStore((set, get) => ({
1354
1379
  _pausedUntil: 0,
1355
1380
  push(event) {
1356
1381
  const { config, buffer } = get();
1382
+ const storeTtl = config.dedupeStoreTtl ?? DEFAULT_DEDUPE_STORE_TTL;
1383
+ const dedupeKey = _pushDedupeKey(event);
1384
+ if (_isRecentPush(dedupeKey, storeTtl)) return;
1357
1385
  const maxSize = config.maxBufferSize ?? 20;
1358
1386
  const sanitized = {
1359
1387
  build_id: event.build_id ?? config.buildId ?? `sdk:${MONITOR_VERSION}`,
@@ -1399,9 +1427,6 @@ var monitorStore = createStore((set, get) => ({
1399
1427
  }
1400
1428
  }));
1401
1429
 
1402
- // src/client/constants.ts
1403
- var MONITOR_INGEST_PATTERN = /cfg\/monitor\/ingest/;
1404
-
1405
1430
  // src/client/capture/js-errors.ts
1406
1431
  var MSG_MAX = 2e3;
1407
1432
  function truncate(s, max = MSG_MAX) {
@@ -1424,12 +1449,12 @@ function isHydrationNoise(msg) {
1424
1449
  return HYDRATION_NOISE.some((p) => p.test(msg));
1425
1450
  }
1426
1451
  __name(isHydrationNoise, "isHydrationNoise");
1427
- var CLIENT_DEDUP_TTL = 5 * 60 * 1e3;
1428
1452
  var recentFingerprints = /* @__PURE__ */ new Map();
1429
1453
  function isRecentlySent(fingerprint) {
1454
+ const ttl = monitorStore.getState().config.dedupeTtl ?? DEFAULT_DEDUPE_TTL;
1430
1455
  const now = Date.now();
1431
1456
  const last = recentFingerprints.get(fingerprint);
1432
- if (last !== void 0 && now - last < CLIENT_DEDUP_TTL) return true;
1457
+ if (last !== void 0 && now - last < ttl) return true;
1433
1458
  recentFingerprints.set(fingerprint, now);
1434
1459
  if (recentFingerprints.size > 100) {
1435
1460
  const oldest = [...recentFingerprints.entries()].sort((a, b) => a[1] - b[1])[0];
@@ -1514,6 +1539,20 @@ var typeMap = {
1514
1539
  error: "ERROR" /* ERROR */
1515
1540
  };
1516
1541
  var ARG_MAX = 500;
1542
+ var recentConsoleFingerprints = /* @__PURE__ */ new Map();
1543
+ function isRecentConsole(fingerprint) {
1544
+ const ttl = monitorStore.getState().config.dedupeTtl ?? DEFAULT_DEDUPE_TTL;
1545
+ const now = Date.now();
1546
+ const last = recentConsoleFingerprints.get(fingerprint);
1547
+ if (last !== void 0 && now - last < ttl) return true;
1548
+ recentConsoleFingerprints.set(fingerprint, now);
1549
+ if (recentConsoleFingerprints.size > 100) {
1550
+ const oldest = [...recentConsoleFingerprints.entries()].sort((a, b) => a[1] - b[1])[0];
1551
+ recentConsoleFingerprints.delete(oldest[0]);
1552
+ }
1553
+ return false;
1554
+ }
1555
+ __name(isRecentConsole, "isRecentConsole");
1517
1556
  function stringifyArg(a) {
1518
1557
  let s;
1519
1558
  if (typeof a === "string") s = a;
@@ -1538,6 +1577,7 @@ async function captureConsoleEvent(level, args) {
1538
1577
  if (MONITOR_INGEST_PATTERN.test(message)) return;
1539
1578
  const url = typeof window !== "undefined" ? window.location.href : "";
1540
1579
  const fingerprint = await computeFingerprint(message, "", url);
1580
+ if (isRecentConsole(fingerprint)) return;
1541
1581
  const { config } = monitorStore.getState();
1542
1582
  monitorStore.getState().push({
1543
1583
  event_type: typeMap[level],
@@ -1590,6 +1630,21 @@ function installConsoleCapture() {
1590
1630
  __name(installConsoleCapture, "installConsoleCapture");
1591
1631
 
1592
1632
  // src/client/capture/validation.ts
1633
+ var recentValidations = /* @__PURE__ */ new Map();
1634
+ function isRecentValidation(key) {
1635
+ const ttl = monitorStore.getState().config.dedupeTtl ?? DEFAULT_DEDUPE_TTL;
1636
+ const now = Date.now();
1637
+ const last = recentValidations.get(key);
1638
+ if (last !== void 0 && now - last < ttl) return true;
1639
+ recentValidations.set(key, now);
1640
+ if (recentValidations.size > 50) {
1641
+ for (const [k, ts] of recentValidations) {
1642
+ if (now - ts > ttl) recentValidations.delete(k);
1643
+ }
1644
+ }
1645
+ return false;
1646
+ }
1647
+ __name(isRecentValidation, "isRecentValidation");
1593
1648
  function installValidationCapture() {
1594
1649
  if (typeof window === "undefined") return () => {
1595
1650
  };
@@ -1597,6 +1652,8 @@ function installValidationCapture() {
1597
1652
  if (!(event instanceof CustomEvent)) return;
1598
1653
  try {
1599
1654
  const detail = event.detail;
1655
+ const dedupeKey = `${detail.operation}:${detail.path}:${detail.method}`;
1656
+ if (isRecentValidation(dedupeKey)) return;
1600
1657
  const { config } = monitorStore.getState();
1601
1658
  const rawMsg = `Zod validation error in ${detail.operation}: ${detail.error?.message ?? "unknown"}`;
1602
1659
  monitorStore.getState().push({
@@ -1621,12 +1678,29 @@ function installValidationCapture() {
1621
1678
  __name(installValidationCapture, "installValidationCapture");
1622
1679
 
1623
1680
  // src/client/capture/network.ts
1681
+ var recentNetworkErrors = /* @__PURE__ */ new Map();
1682
+ function isRecentNetwork(key) {
1683
+ const ttl = monitorStore.getState().config.dedupeTtl ?? DEFAULT_DEDUPE_TTL;
1684
+ const now = Date.now();
1685
+ const last = recentNetworkErrors.get(key);
1686
+ if (last !== void 0 && now - last < ttl) return true;
1687
+ recentNetworkErrors.set(key, now);
1688
+ if (recentNetworkErrors.size > 100) {
1689
+ for (const [k, ts] of recentNetworkErrors) {
1690
+ if (now - ts > ttl) recentNetworkErrors.delete(k);
1691
+ }
1692
+ }
1693
+ return false;
1694
+ }
1695
+ __name(isRecentNetwork, "isRecentNetwork");
1624
1696
  async function monitoredFetch(input, init) {
1625
1697
  const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
1626
1698
  const method = (init?.method ?? "GET").toUpperCase();
1627
1699
  try {
1628
1700
  const response = await fetch(input, init);
1629
1701
  if (!response.ok) {
1702
+ const netKey = `${response.status}:${method}:${url}`;
1703
+ if (isRecentNetwork(netKey)) return response;
1630
1704
  const { config } = monitorStore.getState();
1631
1705
  monitorStore.getState().push({
1632
1706
  event_type: "NETWORK_ERROR" /* NETWORK_ERROR */,
@@ -1644,19 +1718,23 @@ async function monitoredFetch(input, init) {
1644
1718
  }
1645
1719
  return response;
1646
1720
  } catch (err) {
1647
- const { config } = monitorStore.getState();
1648
- monitorStore.getState().push({
1649
- event_type: "NETWORK_ERROR" /* NETWORK_ERROR */,
1650
- level: "error" /* ERROR */,
1651
- message: err instanceof Error ? err.message : `Network error \u2014 ${method} ${url}`,
1652
- url: typeof window !== "undefined" ? window.location.href : "",
1653
- http_method: method,
1654
- http_url: url,
1655
- session_id: getSessionId(),
1656
- user_agent: typeof navigator !== "undefined" ? navigator.userAgent : "",
1657
- project_name: config.project,
1658
- environment: config.environment
1659
- });
1721
+ const errMsg = err instanceof Error ? err.message : "network-error";
1722
+ const netKey = `err:${errMsg.slice(0, 50)}:${method}:${url}`;
1723
+ if (!isRecentNetwork(netKey)) {
1724
+ const { config } = monitorStore.getState();
1725
+ monitorStore.getState().push({
1726
+ event_type: "NETWORK_ERROR" /* NETWORK_ERROR */,
1727
+ level: "error" /* ERROR */,
1728
+ message: err instanceof Error ? err.message : `Network error \u2014 ${method} ${url}`,
1729
+ url: typeof window !== "undefined" ? window.location.href : "",
1730
+ http_method: method,
1731
+ http_url: url,
1732
+ session_id: getSessionId(),
1733
+ user_agent: typeof navigator !== "undefined" ? navigator.userAgent : "",
1734
+ project_name: config.project,
1735
+ environment: config.environment
1736
+ });
1737
+ }
1660
1738
  throw err;
1661
1739
  }
1662
1740
  }