diff --git a/extensions/bluebubbles/src/send.ts b/extensions/bluebubbles/src/send.ts index a85ccc4c4..bc4bb14bd 100644 --- a/extensions/bluebubbles/src/send.ts +++ b/extensions/bluebubbles/src/send.ts @@ -276,6 +276,55 @@ export async function resolveChatGuidForTarget(params: { return participantMatch; } +/** + * Creates a new chat (DM) and optionally sends an initial message. + * Requires Private API to be enabled in BlueBubbles. + */ +async function createNewChatWithMessage(params: { + baseUrl: string; + password: string; + address: string; + message: string; + timeoutMs?: number; +}): Promise { + const url = buildBlueBubblesApiUrl({ + baseUrl: params.baseUrl, + path: "/api/v1/chat/new", + password: params.password, + }); + const payload = { + addresses: [params.address], + message: params.message, + }; + const res = await blueBubblesFetchWithTimeout( + url, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload), + }, + params.timeoutMs, + ); + if (!res.ok) { + const errorText = await res.text(); + // Check for Private API not enabled error + if (res.status === 400 || res.status === 403 || errorText.toLowerCase().includes("private api")) { + throw new Error( + `BlueBubbles send failed: Cannot create new chat - Private API must be enabled. Original error: ${errorText || res.status}`, + ); + } + throw new Error(`BlueBubbles create chat failed (${res.status}): ${errorText || "unknown"}`); + } + const body = await res.text(); + if (!body) return { messageId: "ok" }; + try { + const parsed = JSON.parse(body) as unknown; + return { messageId: extractMessageId(parsed) }; + } catch { + return { messageId: "ok" }; + } +} + export async function sendMessageBlueBubbles( to: string, text: string, @@ -303,6 +352,17 @@ export async function sendMessageBlueBubbles( target, }); if (!chatGuid) { + // If target is a phone number/handle and no existing chat found, + // auto-create a new DM chat using the /api/v1/chat/new endpoint + if (target.kind === "handle") { + return createNewChatWithMessage({ + baseUrl, + password, + address: target.address, + message: trimmedText, + timeoutMs: opts.timeoutMs, + }); + } throw new Error( "BlueBubbles send failed: chatGuid not found for target. Use a chat_guid target or ensure the chat exists.", );