| import type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk/bluebubbles"; |
|
|
| export type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk/bluebubbles"; |
|
|
| export type BlueBubblesGroupConfig = { |
| |
| requireMention?: boolean; |
| |
| tools?: { allow?: string[]; deny?: string[] }; |
| }; |
|
|
| export type BlueBubblesAccountConfig = { |
| |
| name?: string; |
| |
| capabilities?: string[]; |
| |
| configWrites?: boolean; |
| |
| enabled?: boolean; |
| |
| serverUrl?: string; |
| |
| password?: string; |
| |
| webhookPath?: string; |
| |
| dmPolicy?: DmPolicy; |
| allowFrom?: Array<string | number>; |
| |
| groupAllowFrom?: Array<string | number>; |
| |
| groupPolicy?: GroupPolicy; |
| |
| historyLimit?: number; |
| |
| dmHistoryLimit?: number; |
| |
| dms?: Record<string, unknown>; |
| |
| textChunkLimit?: number; |
| |
| chunkMode?: "length" | "newline"; |
| blockStreaming?: boolean; |
| |
| blockStreamingCoalesce?: Record<string, unknown>; |
| |
| mediaMaxMb?: number; |
| |
| |
| |
| |
| mediaLocalRoots?: string[]; |
| |
| sendReadReceipts?: boolean; |
| |
| allowPrivateNetwork?: boolean; |
| |
| groups?: Record<string, BlueBubblesGroupConfig>; |
| }; |
|
|
| export type BlueBubblesActionConfig = { |
| reactions?: boolean; |
| edit?: boolean; |
| unsend?: boolean; |
| reply?: boolean; |
| sendWithEffect?: boolean; |
| renameGroup?: boolean; |
| addParticipant?: boolean; |
| removeParticipant?: boolean; |
| leaveGroup?: boolean; |
| sendAttachment?: boolean; |
| }; |
|
|
| export type BlueBubblesConfig = { |
| |
| accounts?: Record<string, BlueBubblesAccountConfig>; |
| |
| defaultAccount?: string; |
| |
| actions?: BlueBubblesActionConfig; |
| } & BlueBubblesAccountConfig; |
|
|
| export type BlueBubblesSendTarget = |
| | { kind: "chat_id"; chatId: number } |
| | { kind: "chat_guid"; chatGuid: string } |
| | { kind: "chat_identifier"; chatIdentifier: string } |
| | { kind: "handle"; address: string; service?: "imessage" | "sms" | "auto" }; |
|
|
| export type BlueBubblesAttachment = { |
| guid?: string; |
| uti?: string; |
| mimeType?: string; |
| transferName?: string; |
| totalBytes?: number; |
| height?: number; |
| width?: number; |
| originalROWID?: number; |
| }; |
|
|
| const DEFAULT_TIMEOUT_MS = 10_000; |
|
|
| export function normalizeBlueBubblesServerUrl(raw: string): string { |
| const trimmed = raw.trim(); |
| if (!trimmed) { |
| throw new Error("BlueBubbles serverUrl is required"); |
| } |
| const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `http://${trimmed}`; |
| return withScheme.replace(/\/+$/, ""); |
| } |
|
|
| export function buildBlueBubblesApiUrl(params: { |
| baseUrl: string; |
| path: string; |
| password?: string; |
| }): string { |
| const normalized = normalizeBlueBubblesServerUrl(params.baseUrl); |
| const url = new URL(params.path, `${normalized}/`); |
| if (params.password) { |
| url.searchParams.set("password", params.password); |
| } |
| return url.toString(); |
| } |
|
|
| export async function blueBubblesFetchWithTimeout( |
| url: string, |
| init: RequestInit, |
| timeoutMs = DEFAULT_TIMEOUT_MS, |
| ) { |
| const controller = new AbortController(); |
| const timer = setTimeout(() => controller.abort(), timeoutMs); |
| try { |
| return await fetch(url, { ...init, signal: controller.signal }); |
| } finally { |
| clearTimeout(timer); |
| } |
| } |
|
|