mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-06 05:49:12 +02:00
* fix(realtime): drop WS frames without a string type (MUL-3418)
The onmessage handler dispatched every parsed frame to onAny and the
ws.on subscribers without validating its shape. A frame whose parsed JSON
lacked a string `type` (an out-of-protocol frame injected by a proxy /
extension, or a bare JSON primitive) reached the realtime-sync onAny
dispatcher, where `msg.type.split(":")` threw an uncaught TypeError out of
onmessage. The browser reported it via window.onerror, flooding PostHog
`$exception` (~12k events). Non-fatal (no crash, connection stays up), but
pure noise.
Validate once at this trust boundary: a frame must be an object carrying a
string `type`, otherwise drop it as a no-op. The bad-frame log is
rate-limited to one entry per connection — a misbehaving source can repeat
the frame hundreds of times per session.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
* feat(analytics): drop benign ResizeObserver exceptions from telemetry
ResizeObserver "loop ..." errors are the dominant `$exception` bucket
(~31k events / ~1.5k users). They are a benign, self-recovering browser
quirk with no actionable signal and otherwise drown real failures and burn
the event budget. Drop them entirely in before_send (ahead of redaction
and the dedupe fuse, which only caps repeats). The match is narrow — only
the benign "loop" phrasing — so a genuine ResizeObserver bug still reports.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { isBenignException } from "./benign-exceptions";
|
|
|
|
describe("isBenignException", () => {
|
|
it("drops ResizeObserver loop errors via $exception_list value", () => {
|
|
expect(
|
|
isBenignException({
|
|
$exception_list: [
|
|
{
|
|
type: "Error",
|
|
value: "ResizeObserver loop completed with undelivered notifications.",
|
|
},
|
|
],
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("drops the older 'loop limit exceeded' phrasing", () => {
|
|
expect(
|
|
isBenignException({
|
|
$exception_list: [
|
|
{ type: "Error", value: "ResizeObserver loop limit exceeded" },
|
|
],
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("drops when the signal is on the top-level $exception_message", () => {
|
|
expect(
|
|
isBenignException({
|
|
$exception_message: "ResizeObserver loop limit exceeded",
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("matches case-insensitively", () => {
|
|
expect(
|
|
isBenignException({ $exception_message: "resizeobserver LOOP limit exceeded" }),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("keeps real errors", () => {
|
|
expect(
|
|
isBenignException({
|
|
$exception_list: [
|
|
{
|
|
type: "TypeError",
|
|
value: "Cannot read properties of undefined (reading 'split')",
|
|
},
|
|
],
|
|
}),
|
|
).toBe(false);
|
|
});
|
|
|
|
it("does not match an unrelated mention of ResizeObserver", () => {
|
|
// Only the benign "loop" phrasing is silenced; a genuine bug in
|
|
// ResizeObserver usage must still be reported.
|
|
expect(
|
|
isBenignException({
|
|
$exception_message: "ResizeObserver is not defined",
|
|
}),
|
|
).toBe(false);
|
|
});
|
|
|
|
it("fails open on missing or malformed properties", () => {
|
|
expect(isBenignException(undefined)).toBe(false);
|
|
expect(isBenignException({})).toBe(false);
|
|
expect(isBenignException({ $exception_list: "not-an-array" })).toBe(false);
|
|
expect(isBenignException({ $exception_list: [null, 42, {}] })).toBe(false);
|
|
expect(isBenignException({ $exception_message: 123 })).toBe(false);
|
|
});
|
|
});
|