@djangocfg/monitor 2.1.225 → 2.1.227

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
@@ -1127,7 +1127,7 @@ var FrontendEventIngestRequestSchema = z.object({
1127
1127
  event_type: z.nativeEnum(FrontendEventIngestRequestEventType),
1128
1128
  message: z.string().min(1).max(5e3),
1129
1129
  level: z.nativeEnum(FrontendEventIngestRequestLevel).optional(),
1130
- stack_trace: z.string().max(2e4).optional(),
1130
+ stack_trace: z.string().max(1e4).optional(),
1131
1131
  url: z.string().max(2e3).optional(),
1132
1132
  fingerprint: z.string().max(64).optional(),
1133
1133
  http_status: z.number().int().nullable().optional(),
@@ -1138,7 +1138,8 @@ var FrontendEventIngestRequestSchema = z.object({
1138
1138
  browser_fingerprint: z.string().max(64).optional(),
1139
1139
  extra: z.record(z.string(), z.any()).optional(),
1140
1140
  project_name: z.string().max(100).optional(),
1141
- environment: z.string().max(20).optional()
1141
+ environment: z.string().max(20).optional(),
1142
+ build_id: z.string().max(100).optional()
1142
1143
  });
1143
1144
 
1144
1145
  // src/_api/generated/cfg_monitor/_utils/schemas/IngestBatchRequest.schema.ts
@@ -1345,7 +1346,22 @@ var monitorStore = createStore((set, get) => ({
1345
1346
  push(event) {
1346
1347
  const { config, buffer } = get();
1347
1348
  const maxSize = config.maxBufferSize ?? 20;
1348
- const next = [...buffer, event];
1349
+ const sanitized = {
1350
+ ...event,
1351
+ // Enforce field size limits before buffering (last-resort backstop)
1352
+ message: event.message && event.message.length > 4997 ? event.message.slice(0, 4997) + "..." : event.message,
1353
+ stack_trace: event.stack_trace && event.stack_trace.length > 1e4 ? event.stack_trace.slice(0, 9997) + "..." : event.stack_trace,
1354
+ // Cap extra payload — drop entirely if serialized size exceeds 32KB
1355
+ extra: (() => {
1356
+ if (!event.extra) return event.extra;
1357
+ try {
1358
+ return JSON.stringify(event.extra).length > 32768 ? {} : event.extra;
1359
+ } catch {
1360
+ return {};
1361
+ }
1362
+ })()
1363
+ };
1364
+ const next = [...buffer, sanitized];
1349
1365
  set({ buffer: next });
1350
1366
  if (next.length >= maxSize || event.level === "error") {
1351
1367
  get().flush();
@@ -1364,15 +1380,48 @@ var monitorStore = createStore((set, get) => ({
1364
1380
  }));
1365
1381
 
1366
1382
  // src/client/capture/js-errors.ts
1383
+ var MSG_MAX = 2e3;
1384
+ function truncate(s, max = MSG_MAX) {
1385
+ return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
1386
+ }
1387
+ __name(truncate, "truncate");
1388
+ var HYDRATION_NOISE = [
1389
+ /hydration failed/i,
1390
+ /there was an error while hydrating/i,
1391
+ /minified react error #418/i,
1392
+ /minified react error #423/i,
1393
+ /minified react error #425/i,
1394
+ /text content does not match server-rendered html/i
1395
+ ];
1396
+ function isHydrationNoise(msg) {
1397
+ return HYDRATION_NOISE.some((p) => p.test(msg));
1398
+ }
1399
+ __name(isHydrationNoise, "isHydrationNoise");
1400
+ var CLIENT_DEDUP_TTL = 5 * 60 * 1e3;
1401
+ var recentFingerprints = /* @__PURE__ */ new Map();
1402
+ function isRecentlySent(fingerprint) {
1403
+ const now = Date.now();
1404
+ const last = recentFingerprints.get(fingerprint);
1405
+ if (last !== void 0 && now - last < CLIENT_DEDUP_TTL) return true;
1406
+ recentFingerprints.set(fingerprint, now);
1407
+ if (recentFingerprints.size > 100) {
1408
+ const oldest = [...recentFingerprints.entries()].sort((a, b) => a[1] - b[1])[0];
1409
+ recentFingerprints.delete(oldest[0]);
1410
+ }
1411
+ return false;
1412
+ }
1413
+ __name(isRecentlySent, "isRecentlySent");
1367
1414
  function installJsErrorCapture() {
1368
1415
  if (typeof window === "undefined") return () => {
1369
1416
  };
1370
1417
  const onError = /* @__PURE__ */ __name(async (message, source, lineno, colno, error) => {
1371
1418
  try {
1372
- const msg = typeof message === "string" ? message : String(message);
1419
+ const msg = truncate(typeof message === "string" ? message : String(message));
1420
+ if (isHydrationNoise(msg)) return;
1373
1421
  const stack = error?.stack ?? `at ${source}:${lineno}:${colno}`;
1374
1422
  const url = window.location.href;
1375
1423
  const fingerprint = await computeFingerprint(msg, stack, url);
1424
+ if (isRecentlySent(fingerprint)) return;
1376
1425
  const { config } = monitorStore.getState();
1377
1426
  monitorStore.getState().push({
1378
1427
  event_type: "JS_ERROR" /* JS_ERROR */,
@@ -1393,10 +1442,12 @@ function installJsErrorCapture() {
1393
1442
  const onUnhandledRejection = /* @__PURE__ */ __name(async (e) => {
1394
1443
  try {
1395
1444
  const reason = e.reason;
1396
- const msg = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "Unhandled promise rejection";
1445
+ const msg = truncate(reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "Unhandled promise rejection");
1446
+ if (isHydrationNoise(msg)) return;
1397
1447
  const stack = reason instanceof Error ? reason.stack ?? "" : "";
1398
1448
  const url = window.location.href;
1399
1449
  const fingerprint = await computeFingerprint(msg, stack, url);
1450
+ if (isRecentlySent(fingerprint)) return;
1400
1451
  const { config } = monitorStore.getState();
1401
1452
  monitorStore.getState().push({
1402
1453
  event_type: "JS_ERROR" /* JS_ERROR */,
@@ -1433,16 +1484,23 @@ var typeMap = {
1433
1484
  warn: "WARNING" /* WARNING */,
1434
1485
  error: "ERROR" /* ERROR */
1435
1486
  };
1436
- function stringify(args) {
1437
- return args.map((a) => {
1438
- if (typeof a === "string") return a;
1439
- if (a instanceof Error) return a.message;
1487
+ var ARG_MAX = 500;
1488
+ function stringifyArg(a) {
1489
+ let s;
1490
+ if (typeof a === "string") s = a;
1491
+ else if (a instanceof Error) s = a.message;
1492
+ else {
1440
1493
  try {
1441
- return JSON.stringify(a);
1494
+ s = JSON.stringify(a);
1442
1495
  } catch {
1443
- return String(a);
1496
+ s = String(a);
1444
1497
  }
1445
- }).join(" ");
1498
+ }
1499
+ return s.length > ARG_MAX ? s.slice(0, ARG_MAX - 1) + "\u2026" : s;
1500
+ }
1501
+ __name(stringifyArg, "stringifyArg");
1502
+ function stringify(args) {
1503
+ return args.map(stringifyArg).join(" ");
1446
1504
  }
1447
1505
  __name(stringify, "stringify");
1448
1506
  async function captureConsoleEvent(level, args) {
@@ -1510,10 +1568,11 @@ function installValidationCapture() {
1510
1568
  try {
1511
1569
  const detail = event.detail;
1512
1570
  const { config } = monitorStore.getState();
1571
+ const rawMsg = `Zod validation error in ${detail.operation}: ${detail.error?.message ?? "unknown"}`;
1513
1572
  monitorStore.getState().push({
1514
1573
  event_type: "WARNING" /* WARNING */,
1515
1574
  level: "warn" /* WARN */,
1516
- message: `Zod validation error in ${detail.operation}: ${detail.error?.message ?? "unknown"}`,
1575
+ message: rawMsg.length > 500 ? rawMsg.slice(0, 499) + "\u2026" : rawMsg,
1517
1576
  url: window.location.href,
1518
1577
  http_method: detail.method,
1519
1578
  http_url: detail.path,