{"release_id":"01a1998d-9802-0000-b0f7-33a23307f4ed","chunk_id":"01a1998d-9821-7a22-9a57-d3732c901a8f","file":"BNfZi2x3.mjs","mappings":"wVAIO,SAASA,EAAkBC,EAA2C,CAC5E,OAAQA,EAAA,CACP,IAAK,OACJ,OAAOC,EAAI,2CAA2C,EACvD,IAAK,YACJ,OAAOA,EAAI,uBAAuB,EACnC,IAAK,SACJ,OAAOA,EAAI,2BAA2B,EAKvC,IAAK,UACJ,OAAOA,EAAI,mCAAmC,EAC/C,IAAK,kBACJ,OAAOA,EAAI,iCAAiC,EAC7C,IAAK,aACJ,OAAOA,EAAI,yBAAyB,EACrC,IAAK,cACJ,OAAOA,EAAI,2BAA2B,EACvC,QACC,OAAOD,GAAUC,EAAI,aAAa,CAAA,CAErC,CAMO,SAASC,EAAuBC,EAAyB,CAC/D,OAAOA,IAAW,KAAOA,IAAW,GACrC,CAMA,MAAMC,EACL,iHAiBM,SAASC,EAAeC,EAAuB,CAErD,GAAIA,aAAe,cAAgBA,EAAI,OAAS,aAAc,MAAO,GACrE,MAAML,EAAMK,aAAe,MAAQA,EAAI,QAAU,OAAOA,GAAQ,SAAWA,EAAM,GACjF,OAAOF,EAAgB,KAAKH,CAAG,CAChC,CAKO,SAASM,EAAcD,EAAcE,EAA0B,CACrE,OAAKH,EAAeC,CAAG,GAKvB,QAAQ,MAAM,oDAAqDA,CAAG,EAC/DL,EAAI,gCAAgC,GANVO,CAOlC","names":["chatSendErrorText","reason","msg","isPermanentSendFailure","status","NETWORK_MESSAGE","isNetworkError","err","sendErrorText","fallback"],"sources":["../../../../../../src/lib/chat/send-error.ts"],"sourcesContent":["import { msg } from '$lib/i18n/mark';\n\n// RAT-392: map the chat send-gate error codes (returned by the message\n// endpoints when the flood gate trips) to friendly inline copy.\nexport function chatSendErrorText(reason: string | null | undefined): string {\n\tswitch (reason) {\n\t\tcase 'rate':\n\t\t\treturn msg(\"whoa, slow down — you're sending too fast\");\n\t\tcase 'duplicate':\n\t\t\treturn msg('you already sent that');\n\t\tcase 'banned':\n\t\t\treturn msg('your account is suspended');\n\t\t// Definitive 403s from the send endpoints. Before these were mapped, the\n\t\t// endpoints threw errors that serialized to {message}, the client read\n\t\t// {error}, and every one fell through to the generic \"send failed\" default —\n\t\t// so a permanent block read as a transient glitch the user kept retrying.\n\t\tcase 'blocked':\n\t\t\treturn msg('messaging is blocked in this chat');\n\t\tcase 'not_participant':\n\t\t\treturn msg(\"you're not in this conversation\");\n\t\tcase 'not_member':\n\t\t\treturn msg(\"you're not in this room\");\n\t\tcase 'admins_only':\n\t\t\treturn msg('only admins can post here');\n\t\tdefault:\n\t\t\treturn reason || msg('send failed');\n\t}\n}\n\n/** Whether a send rejection can never succeed on retry (a block, a non-member /\n *  non-admin room, a banned account). The client uses this to park the failed\n *  bubble terminally instead of offering a retry that will only fail again. A\n *  network drop or a rate-limit is transient and is NOT permanent. */\nexport function isPermanentSendFailure(status: number): boolean {\n\treturn status === 401 || status === 403;\n}\n\n/** The browser-specific message a failed `fetch()` rejects with: \"Load failed\"\n *  (iOS Safari), \"Failed to fetch\" (Chrome), \"NetworkError when attempting to\n *  fetch resource.\" (Firefox), \"Network request failed\" (some webviews), \"The\n *  Internet connection appears to be offline.\" (Safari, offline). */\nconst NETWORK_MESSAGE =\n\t/load failed|failed to fetch|networkerror|network request failed|the internet connection appears to be offline/i;\n\n/** `fetch()` rejects with a TypeError when the request never completes —\n *  connection drop, DNS failure, offline, a CORS/redirect the browser refuses.\n *  The message is browser-specific and opaque (\"Load failed\" on iOS Safari,\n *  \"Failed to fetch\" on Chrome), and dumping it straight into a send/rate error\n *  read as gibberish to users mid-action (they'd re-tap thinking the button\n *  broke). This detects that class so callers can swap in friendly retry copy.\n *\n *  Matching on `instanceof TypeError` ALONE is not enough: a genuine bug inside\n *  the caller's (large) try block throws a TypeError too — a bad `.map`, a\n *  destructure of undefined. Those would render \"connection dropped — try\n *  again\", telling the user to retry something deterministically broken while\n *  hiding the bug. So the message has to look fetch-shaped as well.\n *\n *  AbortError (a DOMException) is intentionally NOT treated as a network error —\n *  a user-cancelled request shouldn't nag them to retry. */\nexport function isNetworkError(err: unknown): boolean {\n\t// Checked first so no message heuristic can ever reclaim a cancelled request.\n\tif (err instanceof DOMException && err.name === 'AbortError') return false;\n\tconst msg = err instanceof Error ? err.message : typeof err === 'string' ? err : '';\n\treturn NETWORK_MESSAGE.test(msg);\n}\n\n/** Pick the copy to show when a client action's `try/catch` fires. Network\n *  failures get a shared \"connection dropped\" retry line; everything else falls\n *  back to the caller's action-specific message. */\nexport function sendErrorText(err: unknown, fallback: string): string {\n\tif (!isNetworkError(err)) return fallback;\n\t// Every call site *catches* its error, so PostHog's `capture_exceptions`\n\t// (uncaught rejections only) never sees these — the raw message rendered in\n\t// the UI was the sole trace they left. Log here, in the one place that swaps\n\t// the copy, so friendlier UX isn't a net loss of observability.\n\tconsole.error('[send-error] network failure, showing retry copy:', err);\n\treturn msg('connection dropped — try again');\n}\n"],"version":3}