@openclaw/bluebubbles 2026.3.2 → 2026.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +2 -2
- package/package.json +4 -1
- package/src/account-resolve.ts +1 -1
- package/src/accounts.ts +7 -36
- package/src/actions.test.ts +1 -1
- package/src/actions.ts +1 -1
- package/src/attachments.test.ts +1 -1
- package/src/attachments.ts +1 -1
- package/src/channel.ts +50 -70
- package/src/chat.ts +46 -39
- package/src/config-apply.ts +77 -0
- package/src/config-schema.test.ts +1 -1
- package/src/config-schema.ts +1 -1
- package/src/history.ts +1 -1
- package/src/media-send.test.ts +1 -1
- package/src/media-send.ts +1 -1
- package/src/monitor-debounce.ts +1 -1
- package/src/monitor-normalize.ts +2 -11
- package/src/monitor-processing.ts +23 -22
- package/src/monitor-shared.ts +1 -1
- package/src/monitor.test.ts +3 -3
- package/src/monitor.ts +126 -138
- package/src/monitor.webhook-auth.test.ts +77 -172
- package/src/monitor.webhook-route.test.ts +1 -1
- package/src/onboarding.secret-input.test.ts +10 -2
- package/src/onboarding.ts +29 -67
- package/src/probe.ts +1 -1
- package/src/reactions.ts +1 -1
- package/src/request-url.ts +1 -12
- package/src/runtime.ts +1 -1
- package/src/secret-input.ts +8 -14
- package/src/send.test.ts +1 -1
- package/src/send.ts +17 -22
- package/src/targets.ts +1 -1
- package/src/types.ts +2 -2
package/src/onboarding.ts
CHANGED
|
@@ -4,20 +4,21 @@ import type {
|
|
|
4
4
|
OpenClawConfig,
|
|
5
5
|
DmPolicy,
|
|
6
6
|
WizardPrompter,
|
|
7
|
-
} from "openclaw/plugin-sdk";
|
|
7
|
+
} from "openclaw/plugin-sdk/bluebubbles";
|
|
8
8
|
import {
|
|
9
9
|
DEFAULT_ACCOUNT_ID,
|
|
10
|
-
addWildcardAllowFrom,
|
|
11
10
|
formatDocsLink,
|
|
12
11
|
mergeAllowFromEntries,
|
|
13
12
|
normalizeAccountId,
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
resolveAccountIdForConfigure,
|
|
14
|
+
setTopLevelChannelDmPolicyWithAllowFrom,
|
|
15
|
+
} from "openclaw/plugin-sdk/bluebubbles";
|
|
16
16
|
import {
|
|
17
17
|
listBlueBubblesAccountIds,
|
|
18
18
|
resolveBlueBubblesAccount,
|
|
19
19
|
resolveDefaultBlueBubblesAccountId,
|
|
20
20
|
} from "./accounts.js";
|
|
21
|
+
import { applyBlueBubblesConnectionConfig } from "./config-apply.js";
|
|
21
22
|
import { hasConfiguredSecretInput, normalizeSecretInputString } from "./secret-input.js";
|
|
22
23
|
import { parseBlueBubblesAllowTarget } from "./targets.js";
|
|
23
24
|
import { normalizeBlueBubblesServerUrl } from "./types.js";
|
|
@@ -25,19 +26,11 @@ import { normalizeBlueBubblesServerUrl } from "./types.js";
|
|
|
25
26
|
const channel = "bluebubbles" as const;
|
|
26
27
|
|
|
27
28
|
function setBlueBubblesDmPolicy(cfg: OpenClawConfig, dmPolicy: DmPolicy): OpenClawConfig {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
...cfg.channels,
|
|
34
|
-
bluebubbles: {
|
|
35
|
-
...cfg.channels?.bluebubbles,
|
|
36
|
-
dmPolicy,
|
|
37
|
-
...(allowFrom ? { allowFrom } : {}),
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
};
|
|
29
|
+
return setTopLevelChannelDmPolicyWithAllowFrom({
|
|
30
|
+
cfg,
|
|
31
|
+
channel: "bluebubbles",
|
|
32
|
+
dmPolicy,
|
|
33
|
+
});
|
|
41
34
|
}
|
|
42
35
|
|
|
43
36
|
function setBlueBubblesAllowFrom(
|
|
@@ -159,21 +152,16 @@ export const blueBubblesOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
159
152
|
};
|
|
160
153
|
},
|
|
161
154
|
configure: async ({ cfg, prompter, accountOverrides, shouldPromptAccountIds }) => {
|
|
162
|
-
const blueBubblesOverride = accountOverrides.bluebubbles?.trim();
|
|
163
155
|
const defaultAccountId = resolveDefaultBlueBubblesAccountId(cfg);
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
listAccountIds: listBlueBubblesAccountIds,
|
|
174
|
-
defaultAccountId,
|
|
175
|
-
});
|
|
176
|
-
}
|
|
156
|
+
const accountId = await resolveAccountIdForConfigure({
|
|
157
|
+
cfg,
|
|
158
|
+
prompter,
|
|
159
|
+
label: "BlueBubbles",
|
|
160
|
+
accountOverride: accountOverrides.bluebubbles,
|
|
161
|
+
shouldPromptAccountIds,
|
|
162
|
+
listAccountIds: listBlueBubblesAccountIds,
|
|
163
|
+
defaultAccountId,
|
|
164
|
+
});
|
|
177
165
|
|
|
178
166
|
let next = cfg;
|
|
179
167
|
const resolvedAccount = resolveBlueBubblesAccount({ cfg: next, accountId });
|
|
@@ -283,42 +271,16 @@ export const blueBubblesOnboardingAdapter: ChannelOnboardingAdapter = {
|
|
|
283
271
|
}
|
|
284
272
|
|
|
285
273
|
// Apply config
|
|
286
|
-
|
|
287
|
-
next
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
webhookPath,
|
|
297
|
-
},
|
|
298
|
-
},
|
|
299
|
-
};
|
|
300
|
-
} else {
|
|
301
|
-
next = {
|
|
302
|
-
...next,
|
|
303
|
-
channels: {
|
|
304
|
-
...next.channels,
|
|
305
|
-
bluebubbles: {
|
|
306
|
-
...next.channels?.bluebubbles,
|
|
307
|
-
enabled: true,
|
|
308
|
-
accounts: {
|
|
309
|
-
...next.channels?.bluebubbles?.accounts,
|
|
310
|
-
[accountId]: {
|
|
311
|
-
...next.channels?.bluebubbles?.accounts?.[accountId],
|
|
312
|
-
enabled: next.channels?.bluebubbles?.accounts?.[accountId]?.enabled ?? true,
|
|
313
|
-
serverUrl,
|
|
314
|
-
password,
|
|
315
|
-
webhookPath,
|
|
316
|
-
},
|
|
317
|
-
},
|
|
318
|
-
},
|
|
319
|
-
},
|
|
320
|
-
};
|
|
321
|
-
}
|
|
274
|
+
next = applyBlueBubblesConnectionConfig({
|
|
275
|
+
cfg: next,
|
|
276
|
+
accountId,
|
|
277
|
+
patch: {
|
|
278
|
+
serverUrl,
|
|
279
|
+
password,
|
|
280
|
+
webhookPath,
|
|
281
|
+
},
|
|
282
|
+
accountEnabled: "preserve-or-true",
|
|
283
|
+
});
|
|
322
284
|
|
|
323
285
|
await prompter.note(
|
|
324
286
|
[
|
package/src/probe.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BaseProbeResult } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { BaseProbeResult } from "openclaw/plugin-sdk/bluebubbles";
|
|
2
2
|
import { normalizeSecretInputString } from "./secret-input.js";
|
|
3
3
|
import { buildBlueBubblesApiUrl, blueBubblesFetchWithTimeout } from "./types.js";
|
|
4
4
|
|
package/src/reactions.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/bluebubbles";
|
|
2
2
|
import { resolveBlueBubblesServerAccount } from "./account-resolve.js";
|
|
3
3
|
import { getCachedBlueBubblesPrivateApiStatus } from "./probe.js";
|
|
4
4
|
import { blueBubblesFetchWithTimeout, buildBlueBubblesApiUrl } from "./types.js";
|
package/src/request-url.ts
CHANGED
|
@@ -1,12 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
if (typeof input === "string") {
|
|
3
|
-
return input;
|
|
4
|
-
}
|
|
5
|
-
if (input instanceof URL) {
|
|
6
|
-
return input.toString();
|
|
7
|
-
}
|
|
8
|
-
if (typeof input === "object" && input && "url" in input && typeof input.url === "string") {
|
|
9
|
-
return input.url;
|
|
10
|
-
}
|
|
11
|
-
return String(input);
|
|
12
|
-
}
|
|
1
|
+
export { resolveRequestUrl } from "openclaw/plugin-sdk/bluebubbles";
|
package/src/runtime.ts
CHANGED
package/src/secret-input.ts
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
buildSecretInputSchema,
|
|
2
3
|
hasConfiguredSecretInput,
|
|
3
4
|
normalizeResolvedSecretInputString,
|
|
4
5
|
normalizeSecretInputString,
|
|
5
|
-
} from "openclaw/plugin-sdk";
|
|
6
|
-
import { z } from "zod";
|
|
6
|
+
} from "openclaw/plugin-sdk/bluebubbles";
|
|
7
7
|
|
|
8
|
-
export {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
source: z.enum(["env", "file", "exec"]),
|
|
15
|
-
provider: z.string().min(1),
|
|
16
|
-
id: z.string().min(1),
|
|
17
|
-
}),
|
|
18
|
-
]);
|
|
19
|
-
}
|
|
8
|
+
export {
|
|
9
|
+
buildSecretInputSchema,
|
|
10
|
+
hasConfiguredSecretInput,
|
|
11
|
+
normalizeResolvedSecretInputString,
|
|
12
|
+
normalizeSecretInputString,
|
|
13
|
+
};
|
package/src/send.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { PluginRuntime } from "openclaw/plugin-sdk/bluebubbles";
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
3
|
import "./test-mocks.js";
|
|
4
4
|
import { getCachedBlueBubblesPrivateApiStatus } from "./probe.js";
|
package/src/send.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
-
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
3
|
-
import { stripMarkdown } from "openclaw/plugin-sdk";
|
|
2
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/bluebubbles";
|
|
3
|
+
import { stripMarkdown } from "openclaw/plugin-sdk/bluebubbles";
|
|
4
4
|
import { resolveBlueBubblesAccount } from "./accounts.js";
|
|
5
5
|
import {
|
|
6
6
|
getCachedBlueBubblesPrivateApiStatus,
|
|
@@ -108,6 +108,19 @@ function resolvePrivateApiDecision(params: {
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
async function parseBlueBubblesMessageResponse(res: Response): Promise<BlueBubblesSendResult> {
|
|
112
|
+
const body = await res.text();
|
|
113
|
+
if (!body) {
|
|
114
|
+
return { messageId: "ok" };
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const parsed = JSON.parse(body) as unknown;
|
|
118
|
+
return { messageId: extractBlueBubblesMessageId(parsed) };
|
|
119
|
+
} catch {
|
|
120
|
+
return { messageId: "ok" };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
111
124
|
type BlueBubblesChatRecord = Record<string, unknown>;
|
|
112
125
|
|
|
113
126
|
function extractChatGuid(chat: BlueBubblesChatRecord): string | null {
|
|
@@ -342,16 +355,7 @@ async function createNewChatWithMessage(params: {
|
|
|
342
355
|
}
|
|
343
356
|
throw new Error(`BlueBubbles create chat failed (${res.status}): ${errorText || "unknown"}`);
|
|
344
357
|
}
|
|
345
|
-
|
|
346
|
-
if (!body) {
|
|
347
|
-
return { messageId: "ok" };
|
|
348
|
-
}
|
|
349
|
-
try {
|
|
350
|
-
const parsed = JSON.parse(body) as unknown;
|
|
351
|
-
return { messageId: extractBlueBubblesMessageId(parsed) };
|
|
352
|
-
} catch {
|
|
353
|
-
return { messageId: "ok" };
|
|
354
|
-
}
|
|
358
|
+
return parseBlueBubblesMessageResponse(res);
|
|
355
359
|
}
|
|
356
360
|
|
|
357
361
|
export async function sendMessageBlueBubbles(
|
|
@@ -464,14 +468,5 @@ export async function sendMessageBlueBubbles(
|
|
|
464
468
|
const errorText = await res.text();
|
|
465
469
|
throw new Error(`BlueBubbles send failed (${res.status}): ${errorText || "unknown"}`);
|
|
466
470
|
}
|
|
467
|
-
|
|
468
|
-
if (!body) {
|
|
469
|
-
return { messageId: "ok" };
|
|
470
|
-
}
|
|
471
|
-
try {
|
|
472
|
-
const parsed = JSON.parse(body) as unknown;
|
|
473
|
-
return { messageId: extractBlueBubblesMessageId(parsed) };
|
|
474
|
-
} catch {
|
|
475
|
-
return { messageId: "ok" };
|
|
476
|
-
}
|
|
471
|
+
return parseBlueBubblesMessageResponse(res);
|
|
477
472
|
}
|
package/src/targets.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk";
|
|
1
|
+
import type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk/bluebubbles";
|
|
2
2
|
|
|
3
|
-
export type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk";
|
|
3
|
+
export type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk/bluebubbles";
|
|
4
4
|
|
|
5
5
|
export type BlueBubblesGroupConfig = {
|
|
6
6
|
/** If true, only respond in this group when mentioned. */
|