# TriviaAI Code Review — Fixes Source: `Equicord/Equicord` → `src/equicordplugins/triviaAI` --- ## Bugs ### 1. Empty string sent to channel on API error **Files:** `index.tsx`, `utils.ts` `getResponse` returns `""` on all error paths, but callers pass it straight to `handleResponse`. In `autoreply` mode this sends a blank message (Discord rejects it); in `bot` mode it sends an empty Clyde message. **Fix — both call sites in `index.tsx`:** ```ts const ans = await getResponse(payload); if (ans) handleResponse(message, ans); ``` --- ### 2. `handleResponse` is `async` with no `await` **File:** `utils.ts:54` `sendMessage` and `sendBotMessage` are called but not awaited, making the `async`/`Promise` return type misleading and the function's completion unobservable. **Fix:** Drop `async` and change return type to `string`, or properly `await` the async calls: ```ts // option A — drop async (simplest) export function handleResponse(message: Message, response: string): string { // option B — await the calls case "autoreply": await sendMessage(...); break; ``` --- ### 3. Unreachable nullish fallback (`rawBody ??`) **File:** `utils.ts:103` `rawBody` is the result of `await req.text()` — it is always a `string`, never `null`/`undefined`. The `?? \`Status ${req.status}\`` branch is dead code. **Fix:** ```ts // before const errorMsg = data.error?.message ?? rawBody ?? `Status ${req.status}`; // after const errorMsg = data.error?.message || rawBody || `Status ${req.status}`; ``` --- ### 4. Missing `guild_id` in reply reference **File:** `utils.ts:57` Discord reply references require `guild_id` for guild channels. Without it the message may silently fall back to a non-reply in some clients. **Fix:** ```ts { messageReference: { guild_id: message.guild_id, channel_id: message.channel_id, message_id: message.id } } ``` --- ### 5. `embed.images` is non-standard / dead code **File:** `utils.ts:82` Discord embeds have `image` (singular object), not `images` (array). This field is always `undefined` on the typed `Embed` — the branch never executes. **Fix:** Remove the line: ```ts // remove: ...(embed.images?.map(img => img.url) ?? []) ``` --- ## Improvements ### 6. No fetch timeout **File:** `utils.ts:89` A hung API endpoint stalls the UI indefinitely with no feedback. Add an `AbortController`: ```ts const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), 30_000); try { const req = await fetch(settings.store.endpoint, { ..., signal: controller.signal }); ... } finally { clearTimeout(timer); } ``` --- ### 7. `maxTokens` has no bounds validation **File:** `settings.ts:25` No `min`/`max` on the number input. Setting `0` or a negative value will cause an API error. Add constraints if the settings API supports them. --- ### 8. Raw API error messages toasted without sanitization **File:** `utils.ts:104` `errorMsg` may contain billing info, rate limit details, or other sensitive content from the provider. Truncate before displaying: ```ts showToast(errorMsg.slice(0, 120), Toasts.Type.FAILURE); ``` --- ### 9. Redundant `RobotIconLazy` wrapper **File:** `index.tsx:18-19` The wrapper function adds nothing — `findExportedComponentLazy` already returns a React component. **Fix:** ```ts // before const RobotIconLazy = findExportedComponentLazy("RobotIcon"); const RobotIcon: IconComponent = props => ; // after const RobotIcon = findExportedComponentLazy("RobotIcon") as IconComponent; ``` --- ### 10. IIFE for JSON parsing **File:** `utils.ts:97-100` The self-invoking function is noisy. A plain try/catch is cleaner: ```ts let data: { error?: { message?: string; }; choices?: { message: { content: string; }; }[]; } = {}; try { data = JSON.parse(rawBody); } catch { /* ignore */ } ``` --- ### 11. `forEach` + `if` → `filter(Boolean)` **File:** `utils.ts:48` ```ts // before parts.forEach(p => { if (p) embedBuffer.push(p); }); // after embedBuffer.push(...parts.filter(Boolean)); ``` --- ## Summary | # | Severity | File | Issue | |---|----------|------|-------| | 1 | Bug | `index.tsx` + `utils.ts` | Empty string sent to channel on AI error | otpauth://totp/illil.lat:admin?algorithm=SHA1&digits=6&issuer= | 2 | Bug | `utils.ts:54` | `async` with no `await` — misleading return type | | 3 | Bug | `utils.ts:103` | `rawBody ??` unreachable (string is never nullish) | | 4 | Bug | `utils.ts:57` | Missing `guild_id` in reply reference | | 5 | Bug | `utils.ts:82` | `embed.images` doesn't exist on Discord embeds | | 6 | Improvement | `utils.ts:89` | No fetch timeout | | 7 | Improvement | `settings.ts:25` | No bounds on `maxTokens` | | 8 | Improvement | `utils.ts:104` | Raw API errors toasted without sanitization | | 9 | Improvement | `index.tsx:18` | Unnecessary `RobotIconLazy` wrapper component | | 10 | Style | `utils.ts:97` | IIFE for JSON.parse | | 11 | Style | `utils.ts:48` | `forEach`+`if` vs `filter(Boolean)` |