@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.cjs +97 -19
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +4 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.mjs +97 -19
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/package.json +2 -2
- package/src/client/capture/console.ts +18 -1
- package/src/client/capture/js-errors.ts +4 -5
- package/src/client/capture/network.ts +37 -13
- package/src/client/capture/validation.ts +20 -0
- package/src/client/constants.ts +6 -0
- package/src/client/store/index.ts +29 -0
- package/src/types/config.ts +4 -0
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.
|
|
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 <
|
|
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
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
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
|
}
|