@djangocfg/monitor 2.1.237 → 2.1.238

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.mjs CHANGED
@@ -1341,11 +1341,32 @@ __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.238";
1345
1345
 
1346
1346
  // src/client/store/index.ts
1347
1347
  var CIRCUIT_BREAKER_THRESHOLD = 3;
1348
1348
  var CIRCUIT_BREAKER_COOLDOWN_MS = 6e4;
1349
+ var STORE_DEDUP_TTL = 5e3;
1350
+ var STORE_DEDUP_MAX = 200;
1351
+ var _recentPushKeys = /* @__PURE__ */ new Map();
1352
+ function _pushDedupeKey(event) {
1353
+ const msg = (event.message ?? "").slice(0, 100);
1354
+ return `${event.event_type}:${event.level}:${msg}:${event.http_url ?? event.url ?? ""}`;
1355
+ }
1356
+ __name(_pushDedupeKey, "_pushDedupeKey");
1357
+ function _isRecentPush(key) {
1358
+ const now = Date.now();
1359
+ const last = _recentPushKeys.get(key);
1360
+ if (last !== void 0 && now - last < STORE_DEDUP_TTL) return true;
1361
+ _recentPushKeys.set(key, now);
1362
+ if (_recentPushKeys.size > STORE_DEDUP_MAX) {
1363
+ for (const [k, ts] of _recentPushKeys) {
1364
+ if (now - ts > STORE_DEDUP_TTL) _recentPushKeys.delete(k);
1365
+ }
1366
+ }
1367
+ return false;
1368
+ }
1369
+ __name(_isRecentPush, "_isRecentPush");
1349
1370
  var monitorStore = createStore((set, get) => ({
1350
1371
  config: {},
1351
1372
  buffer: [],
@@ -1353,6 +1374,8 @@ var monitorStore = createStore((set, get) => ({
1353
1374
  _consecutiveFailures: 0,
1354
1375
  _pausedUntil: 0,
1355
1376
  push(event) {
1377
+ const dedupeKey = _pushDedupeKey(event);
1378
+ if (_isRecentPush(dedupeKey)) return;
1356
1379
  const { config, buffer } = get();
1357
1380
  const maxSize = config.maxBufferSize ?? 20;
1358
1381
  const sanitized = {
@@ -1514,6 +1537,20 @@ var typeMap = {
1514
1537
  error: "ERROR" /* ERROR */
1515
1538
  };
1516
1539
  var ARG_MAX = 500;
1540
+ var CONSOLE_DEDUP_TTL = 5 * 60 * 1e3;
1541
+ var recentConsoleFingerprints = /* @__PURE__ */ new Map();
1542
+ function isRecentConsole(fingerprint) {
1543
+ const now = Date.now();
1544
+ const last = recentConsoleFingerprints.get(fingerprint);
1545
+ if (last !== void 0 && now - last < CONSOLE_DEDUP_TTL) return true;
1546
+ recentConsoleFingerprints.set(fingerprint, now);
1547
+ if (recentConsoleFingerprints.size > 100) {
1548
+ const oldest = [...recentConsoleFingerprints.entries()].sort((a, b) => a[1] - b[1])[0];
1549
+ recentConsoleFingerprints.delete(oldest[0]);
1550
+ }
1551
+ return false;
1552
+ }
1553
+ __name(isRecentConsole, "isRecentConsole");
1517
1554
  function stringifyArg(a) {
1518
1555
  let s;
1519
1556
  if (typeof a === "string") s = a;
@@ -1538,6 +1575,7 @@ async function captureConsoleEvent(level, args) {
1538
1575
  if (MONITOR_INGEST_PATTERN.test(message)) return;
1539
1576
  const url = typeof window !== "undefined" ? window.location.href : "";
1540
1577
  const fingerprint = await computeFingerprint(message, "", url);
1578
+ if (isRecentConsole(fingerprint)) return;
1541
1579
  const { config } = monitorStore.getState();
1542
1580
  monitorStore.getState().push({
1543
1581
  event_type: typeMap[level],
@@ -1590,6 +1628,21 @@ function installConsoleCapture() {
1590
1628
  __name(installConsoleCapture, "installConsoleCapture");
1591
1629
 
1592
1630
  // src/client/capture/validation.ts
1631
+ var VALIDATION_DEDUP_TTL = 1e4;
1632
+ var recentValidations = /* @__PURE__ */ new Map();
1633
+ function isRecentValidation(key) {
1634
+ const now = Date.now();
1635
+ const last = recentValidations.get(key);
1636
+ if (last !== void 0 && now - last < VALIDATION_DEDUP_TTL) return true;
1637
+ recentValidations.set(key, now);
1638
+ if (recentValidations.size > 50) {
1639
+ for (const [k, ts] of recentValidations) {
1640
+ if (now - ts > VALIDATION_DEDUP_TTL) recentValidations.delete(k);
1641
+ }
1642
+ }
1643
+ return false;
1644
+ }
1645
+ __name(isRecentValidation, "isRecentValidation");
1593
1646
  function installValidationCapture() {
1594
1647
  if (typeof window === "undefined") return () => {
1595
1648
  };
@@ -1597,6 +1650,8 @@ function installValidationCapture() {
1597
1650
  if (!(event instanceof CustomEvent)) return;
1598
1651
  try {
1599
1652
  const detail = event.detail;
1653
+ const dedupeKey = `${detail.operation}:${detail.path}:${detail.method}`;
1654
+ if (isRecentValidation(dedupeKey)) return;
1600
1655
  const { config } = monitorStore.getState();
1601
1656
  const rawMsg = `Zod validation error in ${detail.operation}: ${detail.error?.message ?? "unknown"}`;
1602
1657
  monitorStore.getState().push({
@@ -1621,12 +1676,29 @@ function installValidationCapture() {
1621
1676
  __name(installValidationCapture, "installValidationCapture");
1622
1677
 
1623
1678
  // src/client/capture/network.ts
1679
+ var NETWORK_DEDUP_TTL = 5e3;
1680
+ var recentNetworkErrors = /* @__PURE__ */ new Map();
1681
+ function isRecentNetwork(key) {
1682
+ const now = Date.now();
1683
+ const last = recentNetworkErrors.get(key);
1684
+ if (last !== void 0 && now - last < NETWORK_DEDUP_TTL) return true;
1685
+ recentNetworkErrors.set(key, now);
1686
+ if (recentNetworkErrors.size > 100) {
1687
+ for (const [k, ts] of recentNetworkErrors) {
1688
+ if (now - ts > NETWORK_DEDUP_TTL) recentNetworkErrors.delete(k);
1689
+ }
1690
+ }
1691
+ return false;
1692
+ }
1693
+ __name(isRecentNetwork, "isRecentNetwork");
1624
1694
  async function monitoredFetch(input, init) {
1625
1695
  const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
1626
1696
  const method = (init?.method ?? "GET").toUpperCase();
1627
1697
  try {
1628
1698
  const response = await fetch(input, init);
1629
1699
  if (!response.ok) {
1700
+ const netKey = `${response.status}:${method}:${url}`;
1701
+ if (isRecentNetwork(netKey)) return response;
1630
1702
  const { config } = monitorStore.getState();
1631
1703
  monitorStore.getState().push({
1632
1704
  event_type: "NETWORK_ERROR" /* NETWORK_ERROR */,
@@ -1644,19 +1716,23 @@ async function monitoredFetch(input, init) {
1644
1716
  }
1645
1717
  return response;
1646
1718
  } 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
- });
1719
+ const errMsg = err instanceof Error ? err.message : "network-error";
1720
+ const netKey = `err:${errMsg.slice(0, 50)}:${method}:${url}`;
1721
+ if (!isRecentNetwork(netKey)) {
1722
+ const { config } = monitorStore.getState();
1723
+ monitorStore.getState().push({
1724
+ event_type: "NETWORK_ERROR" /* NETWORK_ERROR */,
1725
+ level: "error" /* ERROR */,
1726
+ message: err instanceof Error ? err.message : `Network error \u2014 ${method} ${url}`,
1727
+ url: typeof window !== "undefined" ? window.location.href : "",
1728
+ http_method: method,
1729
+ http_url: url,
1730
+ session_id: getSessionId(),
1731
+ user_agent: typeof navigator !== "undefined" ? navigator.userAgent : "",
1732
+ project_name: config.project,
1733
+ environment: config.environment
1734
+ });
1735
+ }
1660
1736
  throw err;
1661
1737
  }
1662
1738
  }