From 6756e376f331fbbaec82363bcb9a69ea40630026 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 13 Mar 2026 21:17:59 +0000 Subject: [PATCH] refactor: share bluebubbles response and tapback helpers --- extensions/bluebubbles/src/chat.ts | 22 ++++---- .../bluebubbles/src/monitor-normalize.ts | 51 +++++++++++-------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/extensions/bluebubbles/src/chat.ts b/extensions/bluebubbles/src/chat.ts index b63f09272f2..1670f276ba7 100644 --- a/extensions/bluebubbles/src/chat.ts +++ b/extensions/bluebubbles/src/chat.ts @@ -26,6 +26,14 @@ function assertPrivateApiEnabled(accountId: string, feature: string): void { } } +async function assertBlueBubblesActionOk(response: Response, action: string): Promise { + if (response.ok) { + return; + } + const errorText = await response.text().catch(() => ""); + throw new Error(`BlueBubbles ${action} failed (${response.status}): ${errorText || "unknown"}`); +} + function resolvePartIndex(partIndex: number | undefined): number { return typeof partIndex === "number" ? partIndex : 0; } @@ -55,12 +63,7 @@ async function sendBlueBubblesChatEndpointRequest(params: { { method: params.method }, params.opts.timeoutMs, ); - if (!res.ok) { - const errorText = await res.text().catch(() => ""); - throw new Error( - `BlueBubbles ${params.action} failed (${res.status}): ${errorText || "unknown"}`, - ); - } + await assertBlueBubblesActionOk(res, params.action); } async function sendPrivateApiJsonRequest(params: { @@ -86,12 +89,7 @@ async function sendPrivateApiJsonRequest(params: { } const res = await blueBubblesFetchWithTimeout(url, request, params.opts.timeoutMs); - if (!res.ok) { - const errorText = await res.text().catch(() => ""); - throw new Error( - `BlueBubbles ${params.action} failed (${res.status}): ${errorText || "unknown"}`, - ); - } + await assertBlueBubblesActionOk(res, params.action); } export async function markBlueBubblesChatRead( diff --git a/extensions/bluebubbles/src/monitor-normalize.ts b/extensions/bluebubbles/src/monitor-normalize.ts index 83454602d4c..085bd8923e1 100644 --- a/extensions/bluebubbles/src/monitor-normalize.ts +++ b/extensions/bluebubbles/src/monitor-normalize.ts @@ -582,6 +582,29 @@ export function parseTapbackText(params: { return null; } + const parseLeadingReactionAction = ( + prefix: "reacted" | "removed", + defaultAction: "added" | "removed", + ) => { + if (!lower.startsWith(prefix)) { + return null; + } + const emoji = extractFirstEmoji(trimmed) ?? params.emojiHint; + if (!emoji) { + return null; + } + const quotedText = extractQuotedTapbackText(trimmed); + if (params.requireQuoted && !quotedText) { + return null; + } + const fallback = trimmed.slice(prefix.length).trim(); + return { + emoji, + action: params.actionHint ?? defaultAction, + quotedText: quotedText ?? fallback, + }; + }; + for (const [pattern, { emoji, action }] of TAPBACK_TEXT_MAP) { if (lower.startsWith(pattern)) { // Extract quoted text if present (e.g., 'Loved "hello"' -> "hello") @@ -599,30 +622,14 @@ export function parseTapbackText(params: { } } - if (lower.startsWith("reacted")) { - const emoji = extractFirstEmoji(trimmed) ?? params.emojiHint; - if (!emoji) { - return null; - } - const quotedText = extractQuotedTapbackText(trimmed); - if (params.requireQuoted && !quotedText) { - return null; - } - const fallback = trimmed.slice("reacted".length).trim(); - return { emoji, action: params.actionHint ?? "added", quotedText: quotedText ?? fallback }; + const reacted = parseLeadingReactionAction("reacted", "added"); + if (reacted) { + return reacted; } - if (lower.startsWith("removed")) { - const emoji = extractFirstEmoji(trimmed) ?? params.emojiHint; - if (!emoji) { - return null; - } - const quotedText = extractQuotedTapbackText(trimmed); - if (params.requireQuoted && !quotedText) { - return null; - } - const fallback = trimmed.slice("removed".length).trim(); - return { emoji, action: params.actionHint ?? "removed", quotedText: quotedText ?? fallback }; + const removed = parseLeadingReactionAction("removed", "removed"); + if (removed) { + return removed; } return null; }