@openclaw/bluebubbles 2026.1.29
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 +20 -0
- package/openclaw.plugin.json +11 -0
- package/package.json +33 -0
- package/src/accounts.ts +80 -0
- package/src/actions.test.ts +651 -0
- package/src/actions.ts +403 -0
- package/src/attachments.test.ts +346 -0
- package/src/attachments.ts +282 -0
- package/src/channel.ts +399 -0
- package/src/chat.test.ts +462 -0
- package/src/chat.ts +354 -0
- package/src/config-schema.ts +51 -0
- package/src/media-send.ts +168 -0
- package/src/monitor.test.ts +2146 -0
- package/src/monitor.ts +2276 -0
- package/src/onboarding.ts +340 -0
- package/src/probe.ts +127 -0
- package/src/reactions.test.ts +393 -0
- package/src/reactions.ts +183 -0
- package/src/runtime.ts +14 -0
- package/src/send.test.ts +809 -0
- package/src/send.ts +418 -0
- package/src/targets.test.ts +184 -0
- package/src/targets.ts +323 -0
- package/src/types.ts +127 -0
package/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
3
|
+
|
|
4
|
+
import { bluebubblesPlugin } from "./src/channel.js";
|
|
5
|
+
import { handleBlueBubblesWebhookRequest } from "./src/monitor.js";
|
|
6
|
+
import { setBlueBubblesRuntime } from "./src/runtime.js";
|
|
7
|
+
|
|
8
|
+
const plugin = {
|
|
9
|
+
id: "bluebubbles",
|
|
10
|
+
name: "BlueBubbles",
|
|
11
|
+
description: "BlueBubbles channel plugin (macOS app)",
|
|
12
|
+
configSchema: emptyPluginConfigSchema(),
|
|
13
|
+
register(api: OpenClawPluginApi) {
|
|
14
|
+
setBlueBubblesRuntime(api.runtime);
|
|
15
|
+
api.registerChannel({ plugin: bluebubblesPlugin });
|
|
16
|
+
api.registerHttpHandler(handleBlueBubblesWebhookRequest);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default plugin;
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openclaw/bluebubbles",
|
|
3
|
+
"version": "2026.1.29",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OpenClaw BlueBubbles channel plugin",
|
|
6
|
+
"openclaw": {
|
|
7
|
+
"extensions": [
|
|
8
|
+
"./index.ts"
|
|
9
|
+
],
|
|
10
|
+
"channel": {
|
|
11
|
+
"id": "bluebubbles",
|
|
12
|
+
"label": "BlueBubbles",
|
|
13
|
+
"selectionLabel": "BlueBubbles (macOS app)",
|
|
14
|
+
"detailLabel": "BlueBubbles",
|
|
15
|
+
"docsPath": "/channels/bluebubbles",
|
|
16
|
+
"docsLabel": "bluebubbles",
|
|
17
|
+
"blurb": "iMessage via the BlueBubbles mac app + REST API.",
|
|
18
|
+
"aliases": [
|
|
19
|
+
"bb"
|
|
20
|
+
],
|
|
21
|
+
"preferOver": [
|
|
22
|
+
"imessage"
|
|
23
|
+
],
|
|
24
|
+
"systemImage": "bubble.left.and.text.bubble.right",
|
|
25
|
+
"order": 75
|
|
26
|
+
},
|
|
27
|
+
"install": {
|
|
28
|
+
"npmSpec": "@openclaw/bluebubbles",
|
|
29
|
+
"localPath": "extensions/bluebubbles",
|
|
30
|
+
"defaultChoice": "npm"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
package/src/accounts.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk";
|
|
2
|
+
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "openclaw/plugin-sdk";
|
|
3
|
+
import { normalizeBlueBubblesServerUrl, type BlueBubblesAccountConfig } from "./types.js";
|
|
4
|
+
|
|
5
|
+
export type ResolvedBlueBubblesAccount = {
|
|
6
|
+
accountId: string;
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
name?: string;
|
|
9
|
+
config: BlueBubblesAccountConfig;
|
|
10
|
+
configured: boolean;
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function listConfiguredAccountIds(cfg: OpenClawConfig): string[] {
|
|
15
|
+
const accounts = cfg.channels?.bluebubbles?.accounts;
|
|
16
|
+
if (!accounts || typeof accounts !== "object") return [];
|
|
17
|
+
return Object.keys(accounts).filter(Boolean);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function listBlueBubblesAccountIds(cfg: OpenClawConfig): string[] {
|
|
21
|
+
const ids = listConfiguredAccountIds(cfg);
|
|
22
|
+
if (ids.length === 0) return [DEFAULT_ACCOUNT_ID];
|
|
23
|
+
return ids.sort((a, b) => a.localeCompare(b));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function resolveDefaultBlueBubblesAccountId(cfg: OpenClawConfig): string {
|
|
27
|
+
const ids = listBlueBubblesAccountIds(cfg);
|
|
28
|
+
if (ids.includes(DEFAULT_ACCOUNT_ID)) return DEFAULT_ACCOUNT_ID;
|
|
29
|
+
return ids[0] ?? DEFAULT_ACCOUNT_ID;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resolveAccountConfig(
|
|
33
|
+
cfg: OpenClawConfig,
|
|
34
|
+
accountId: string,
|
|
35
|
+
): BlueBubblesAccountConfig | undefined {
|
|
36
|
+
const accounts = cfg.channels?.bluebubbles?.accounts;
|
|
37
|
+
if (!accounts || typeof accounts !== "object") return undefined;
|
|
38
|
+
return accounts[accountId] as BlueBubblesAccountConfig | undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function mergeBlueBubblesAccountConfig(
|
|
42
|
+
cfg: OpenClawConfig,
|
|
43
|
+
accountId: string,
|
|
44
|
+
): BlueBubblesAccountConfig {
|
|
45
|
+
const base = (cfg.channels?.bluebubbles ?? {}) as BlueBubblesAccountConfig & {
|
|
46
|
+
accounts?: unknown;
|
|
47
|
+
};
|
|
48
|
+
const { accounts: _ignored, ...rest } = base;
|
|
49
|
+
const account = resolveAccountConfig(cfg, accountId) ?? {};
|
|
50
|
+
const chunkMode = account.chunkMode ?? rest.chunkMode ?? "length";
|
|
51
|
+
return { ...rest, ...account, chunkMode };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function resolveBlueBubblesAccount(params: {
|
|
55
|
+
cfg: OpenClawConfig;
|
|
56
|
+
accountId?: string | null;
|
|
57
|
+
}): ResolvedBlueBubblesAccount {
|
|
58
|
+
const accountId = normalizeAccountId(params.accountId);
|
|
59
|
+
const baseEnabled = params.cfg.channels?.bluebubbles?.enabled;
|
|
60
|
+
const merged = mergeBlueBubblesAccountConfig(params.cfg, accountId);
|
|
61
|
+
const accountEnabled = merged.enabled !== false;
|
|
62
|
+
const serverUrl = merged.serverUrl?.trim();
|
|
63
|
+
const password = merged.password?.trim();
|
|
64
|
+
const configured = Boolean(serverUrl && password);
|
|
65
|
+
const baseUrl = serverUrl ? normalizeBlueBubblesServerUrl(serverUrl) : undefined;
|
|
66
|
+
return {
|
|
67
|
+
accountId,
|
|
68
|
+
enabled: baseEnabled !== false && accountEnabled,
|
|
69
|
+
name: merged.name?.trim() || undefined,
|
|
70
|
+
config: merged,
|
|
71
|
+
configured,
|
|
72
|
+
baseUrl,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function listEnabledBlueBubblesAccounts(cfg: OpenClawConfig): ResolvedBlueBubblesAccount[] {
|
|
77
|
+
return listBlueBubblesAccountIds(cfg)
|
|
78
|
+
.map((accountId) => resolveBlueBubblesAccount({ cfg, accountId }))
|
|
79
|
+
.filter((account) => account.enabled);
|
|
80
|
+
}
|