@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.cjs CHANGED
@@ -1144,7 +1144,7 @@ var FrontendEventIngestRequestSchema = import_zod.z.object({
1144
1144
  event_type: import_zod.z.nativeEnum(FrontendEventIngestRequestEventType),
1145
1145
  message: import_zod.z.string().min(1).max(5e3),
1146
1146
  level: import_zod.z.nativeEnum(FrontendEventIngestRequestLevel).optional(),
1147
- stack_trace: import_zod.z.string().max(2e4).optional(),
1147
+ stack_trace: import_zod.z.string().max(1e4).optional(),
1148
1148
  url: import_zod.z.string().max(2e3).optional(),
1149
1149
  fingerprint: import_zod.z.string().max(64).optional(),
1150
1150
  http_status: import_zod.z.number().int().nullable().optional(),
@@ -1155,7 +1155,8 @@ var FrontendEventIngestRequestSchema = import_zod.z.object({
1155
1155
  browser_fingerprint: import_zod.z.string().max(64).optional(),
1156
1156
  extra: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
1157
1157
  project_name: import_zod.z.string().max(100).optional(),
1158
- environment: import_zod.z.string().max(20).optional()
1158
+ environment: import_zod.z.string().max(20).optional(),
1159
+ build_id: import_zod.z.string().max(100).optional()
1159
1160
  });
1160
1161
 
1161
1162
  // src/_api/generated/cfg_monitor/_utils/schemas/IngestBatchRequest.schema.ts
@@ -1362,7 +1363,22 @@ var monitorStore = (0, import_vanilla.createStore)((set, get) => ({
1362
1363
  push(event) {
1363
1364
  const { config, buffer } = get();
1364
1365
  const maxSize = config.maxBufferSize ?? 20;
1365
- const next = [...buffer, event];
1366
+ const sanitized = {
1367
+ ...event,
1368
+ // Enforce field size limits before buffering (last-resort backstop)
1369
+ message: event.message && event.message.length > 4997 ? event.message.slice(0, 4997) + "..." : event.message,
1370
+ stack_trace: event.stack_trace && event.stack_trace.length > 1e4 ? event.stack_trace.slice(0, 9997) + "..." : event.stack_trace,
1371
+ // Cap extra payload — drop entirely if serialized size exceeds 32KB
1372
+ extra: (() => {
1373
+ if (!event.extra) return event.extra;
1374
+ try {
1375
+ return JSON.stringify(event.extra).length > 32768 ? {} : event.extra;
1376
+ } catch {
1377
+ return {};
1378
+ }
1379
+ })()
1380
+ };
1381
+ const next = [...buffer, sanitized];
1366
1382
  set({ buffer: next });
1367
1383
  if (next.length >= maxSize || event.level === "error") {
1368
1384
  get().flush();
@@ -1381,15 +1397,48 @@ var monitorStore = (0, import_vanilla.createStore)((set, get) => ({
1381
1397
  }));
1382
1398
 
1383
1399
  // src/client/capture/js-errors.ts
1400
+ var MSG_MAX = 2e3;
1401
+ function truncate(s, max = MSG_MAX) {
1402
+ return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
1403
+ }
1404
+ __name(truncate, "truncate");
1405
+ var HYDRATION_NOISE = [
1406
+ /hydration failed/i,
1407
+ /there was an error while hydrating/i,
1408
+ /minified react error #418/i,
1409
+ /minified react error #423/i,
1410
+ /minified react error #425/i,
1411
+ /text content does not match server-rendered html/i
1412
+ ];
1413
+ function isHydrationNoise(msg) {
1414
+ return HYDRATION_NOISE.some((p) => p.test(msg));
1415
+ }
1416
+ __name(isHydrationNoise, "isHydrationNoise");
1417
+ var CLIENT_DEDUP_TTL = 5 * 60 * 1e3;
1418
+ var recentFingerprints = /* @__PURE__ */ new Map();
1419
+ function isRecentlySent(fingerprint) {
1420
+ const now = Date.now();
1421
+ const last = recentFingerprints.get(fingerprint);
1422
+ if (last !== void 0 && now - last < CLIENT_DEDUP_TTL) return true;
1423
+ recentFingerprints.set(fingerprint, now);
1424
+ if (recentFingerprints.size > 100) {
1425
+ const oldest = [...recentFingerprints.entries()].sort((a, b) => a[1] - b[1])[0];
1426
+ recentFingerprints.delete(oldest[0]);
1427
+ }
1428
+ return false;
1429
+ }
1430
+ __name(isRecentlySent, "isRecentlySent");
1384
1431
  function installJsErrorCapture() {
1385
1432
  if (typeof window === "undefined") return () => {
1386
1433
  };
1387
1434
  const onError = /* @__PURE__ */ __name(async (message, source, lineno, colno, error) => {
1388
1435
  try {
1389
- const msg = typeof message === "string" ? message : String(message);
1436
+ const msg = truncate(typeof message === "string" ? message : String(message));
1437
+ if (isHydrationNoise(msg)) return;
1390
1438
  const stack = error?.stack ?? `at ${source}:${lineno}:${colno}`;
1391
1439
  const url = window.location.href;
1392
1440
  const fingerprint = await computeFingerprint(msg, stack, url);
1441
+ if (isRecentlySent(fingerprint)) return;
1393
1442
  const { config } = monitorStore.getState();
1394
1443
  monitorStore.getState().push({
1395
1444
  event_type: "JS_ERROR" /* JS_ERROR */,
@@ -1410,10 +1459,12 @@ function installJsErrorCapture() {
1410
1459
  const onUnhandledRejection = /* @__PURE__ */ __name(async (e) => {
1411
1460
  try {
1412
1461
  const reason = e.reason;
1413
- const msg = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "Unhandled promise rejection";
1462
+ const msg = truncate(reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "Unhandled promise rejection");
1463
+ if (isHydrationNoise(msg)) return;
1414
1464
  const stack = reason instanceof Error ? reason.stack ?? "" : "";
1415
1465
  const url = window.location.href;
1416
1466
  const fingerprint = await computeFingerprint(msg, stack, url);
1467
+ if (isRecentlySent(fingerprint)) return;
1417
1468
  const { config } = monitorStore.getState();
1418
1469
  monitorStore.getState().push({
1419
1470
  event_type: "JS_ERROR" /* JS_ERROR */,
@@ -1450,16 +1501,23 @@ var typeMap = {
1450
1501
  warn: "WARNING" /* WARNING */,
1451
1502
  error: "ERROR" /* ERROR */
1452
1503
  };
1453
- function stringify(args) {
1454
- return args.map((a) => {
1455
- if (typeof a === "string") return a;
1456
- if (a instanceof Error) return a.message;
1504
+ var ARG_MAX = 500;
1505
+ function stringifyArg(a) {
1506
+ let s;
1507
+ if (typeof a === "string") s = a;
1508
+ else if (a instanceof Error) s = a.message;
1509
+ else {
1457
1510
  try {
1458
- return JSON.stringify(a);
1511
+ s = JSON.stringify(a);
1459
1512
  } catch {
1460
- return String(a);
1513
+ s = String(a);
1461
1514
  }
1462
- }).join(" ");
1515
+ }
1516
+ return s.length > ARG_MAX ? s.slice(0, ARG_MAX - 1) + "\u2026" : s;
1517
+ }
1518
+ __name(stringifyArg, "stringifyArg");
1519
+ function stringify(args) {
1520
+ return args.map(stringifyArg).join(" ");
1463
1521
  }
1464
1522
  __name(stringify, "stringify");
1465
1523
  async function captureConsoleEvent(level, args) {
@@ -1527,10 +1585,11 @@ function installValidationCapture() {
1527
1585
  try {
1528
1586
  const detail = event.detail;
1529
1587
  const { config } = monitorStore.getState();
1588
+ const rawMsg = `Zod validation error in ${detail.operation}: ${detail.error?.message ?? "unknown"}`;
1530
1589
  monitorStore.getState().push({
1531
1590
  event_type: "WARNING" /* WARNING */,
1532
1591
  level: "warn" /* WARN */,
1533
- message: `Zod validation error in ${detail.operation}: ${detail.error?.message ?? "unknown"}`,
1592
+ message: rawMsg.length > 500 ? rawMsg.slice(0, 499) + "\u2026" : rawMsg,
1534
1593
  url: window.location.href,
1535
1594
  http_method: detail.method,
1536
1595
  http_url: detail.path,