@gloablehive/celphone-wechat-plugin 1.0.0
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/INSTALL.md +231 -0
- package/README.md +259 -0
- package/dist/index-simple.js +9 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +77 -0
- package/dist/mock-server.d.ts +6 -0
- package/dist/mock-server.js +203 -0
- package/dist/openclaw.plugin.json +96 -0
- package/dist/setup-entry.d.ts +9 -0
- package/dist/setup-entry.js +8 -0
- package/dist/src/cache/compactor.d.ts +36 -0
- package/dist/src/cache/compactor.js +154 -0
- package/dist/src/cache/extractor.d.ts +48 -0
- package/dist/src/cache/extractor.js +120 -0
- package/dist/src/cache/index.d.ts +15 -0
- package/dist/src/cache/index.js +16 -0
- package/dist/src/cache/indexer.d.ts +41 -0
- package/dist/src/cache/indexer.js +262 -0
- package/dist/src/cache/manager.d.ts +113 -0
- package/dist/src/cache/manager.js +271 -0
- package/dist/src/cache/message-queue.d.ts +59 -0
- package/dist/src/cache/message-queue.js +147 -0
- package/dist/src/cache/saas-connector.d.ts +94 -0
- package/dist/src/cache/saas-connector.js +289 -0
- package/dist/src/cache/syncer.d.ts +60 -0
- package/dist/src/cache/syncer.js +177 -0
- package/dist/src/cache/types.d.ts +198 -0
- package/dist/src/cache/types.js +43 -0
- package/dist/src/cache/writer.d.ts +81 -0
- package/dist/src/cache/writer.js +461 -0
- package/dist/src/channel.d.ts +65 -0
- package/dist/src/channel.js +334 -0
- package/dist/src/client.d.ts +280 -0
- package/dist/src/client.js +248 -0
- package/index-simple.ts +11 -0
- package/index.ts +89 -0
- package/mock-server.ts +237 -0
- package/openclaw.plugin.json +98 -0
- package/package.json +37 -0
- package/setup-entry.ts +10 -0
- package/src/channel.ts +398 -0
- package/src/client.ts +412 -0
- package/test-cache.ts +260 -0
- package/test-integration.ts +319 -0
- package/tsconfig.json +22 -0
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gloablehive/celphone-wechat-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OpenClaw channel plugin for workphone-wechat API - enables sending/receiving WeChat messages through workphone",
|
|
6
|
+
"main": "index.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "npx tsx test-cache.ts",
|
|
9
|
+
"test:cache": "npx tsx test-cache.ts",
|
|
10
|
+
"test:integration": "npx tsx test-integration.ts",
|
|
11
|
+
"test:mock": "npx tsx mock-server.ts",
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"clean": "rm -rf /tmp/wechat-cache-test*"
|
|
14
|
+
},
|
|
15
|
+
"openclaw": {
|
|
16
|
+
"extensions": [
|
|
17
|
+
"./index.ts"
|
|
18
|
+
],
|
|
19
|
+
"setupEntry": "./setup-entry.ts",
|
|
20
|
+
"channel": {
|
|
21
|
+
"id": "celphone-wechat",
|
|
22
|
+
"label": "WorkPhone WeChat",
|
|
23
|
+
"blurb": "Connect OpenClaw to WorkPhone WeChat API for sending and receiving WeChat messages"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@gloablehive/wechat-cache": "^1.0.0",
|
|
28
|
+
"openclaw": ">=1.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/express": "^4.17.0",
|
|
32
|
+
"@types/node": "^20.0.0",
|
|
33
|
+
"express": "^4.18.0",
|
|
34
|
+
"tsx": "^4.21.0",
|
|
35
|
+
"typescript": "^5.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/setup-entry.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Lightweight entry for loading during onboarding/config when channel is disabled
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/core";
|
|
8
|
+
import { celPhoneWeChatPlugin } from "./src/channel.js";
|
|
9
|
+
|
|
10
|
+
export default defineSetupPluginEntry(celPhoneWeChatPlugin);
|
package/src/channel.ts
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkPhone WeChat Channel Plugin for OpenClaw
|
|
3
|
+
*
|
|
4
|
+
* This channel plugin connects OpenClaw to WorkPhone's WeChat API,
|
|
5
|
+
* enabling sending and receiving WeChat messages through the WorkPhone platform.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT - Human Account Model:
|
|
8
|
+
* Unlike Telegram/WhatsApp bots, this connects to a real human WeChat account.
|
|
9
|
+
* The agent communicates with ALL friends and groups under that WeChat account,
|
|
10
|
+
* not just one DM context. This is "human mode" vs "bot mode".
|
|
11
|
+
*
|
|
12
|
+
* Includes Local Cache:
|
|
13
|
+
* - Per-account, per-user/conversation MD files
|
|
14
|
+
* - YAML frontmatter (aligned with Claude Code)
|
|
15
|
+
* - MEMORY.md indexing
|
|
16
|
+
* - 4-layer compression
|
|
17
|
+
* - AI summary extraction
|
|
18
|
+
* - SAAS connectivity + offline fallback
|
|
19
|
+
* - Cloud sync
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
createChatChannelPlugin,
|
|
24
|
+
createChannelPluginBase,
|
|
25
|
+
} from "openclaw/plugin-sdk/core";
|
|
26
|
+
import type { OpenClawConfig } from "openclaw/plugin-sdk/core";
|
|
27
|
+
import { createWorkPhoneClient, type WebhookPayload } from "./client.js";
|
|
28
|
+
|
|
29
|
+
// Import cache modules from shared package
|
|
30
|
+
import {
|
|
31
|
+
createCacheManager,
|
|
32
|
+
CacheManager,
|
|
33
|
+
WeChatAccount,
|
|
34
|
+
} from "@gloablehive/wechat-cache";
|
|
35
|
+
|
|
36
|
+
// Cache manager instance (lazy initialized)
|
|
37
|
+
let cacheManager: CacheManager | null = null;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get or create cache manager
|
|
41
|
+
*/
|
|
42
|
+
function getCacheManager(cfg: OpenClawConfig): CacheManager {
|
|
43
|
+
if (cacheManager) return cacheManager;
|
|
44
|
+
|
|
45
|
+
const section = (cfg.channels as Record<string, any>)?.["celphone-wechat"];
|
|
46
|
+
const accounts = (section?.accounts || []) as WeChatAccount[];
|
|
47
|
+
|
|
48
|
+
// If no accounts configured, create default from main config
|
|
49
|
+
if (accounts.length === 0 && section?.wechatAccountId) {
|
|
50
|
+
accounts.push({
|
|
51
|
+
accountId: section.accountId || 'default',
|
|
52
|
+
wechatAccountId: section.wechatAccountId,
|
|
53
|
+
wechatId: section.wechatId || section.wechatAccountId,
|
|
54
|
+
nickName: section.nickName || 'WeChat User',
|
|
55
|
+
enabled: true,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const basePath = (globalThis as any)?.process?.env?.OPENCLAW_CACHE_PATH
|
|
60
|
+
|| '~/.openclaw/channels/celphone-wechat';
|
|
61
|
+
|
|
62
|
+
cacheManager = createCacheManager({
|
|
63
|
+
basePath,
|
|
64
|
+
accounts,
|
|
65
|
+
saasConfig: section?.saas ? {
|
|
66
|
+
apiBaseUrl: section.saas.apiBaseUrl,
|
|
67
|
+
apiKey: section.saas.apiKey,
|
|
68
|
+
timeout: section.saas.timeout || 5000,
|
|
69
|
+
} : undefined,
|
|
70
|
+
syncConfig: section?.sync ? {
|
|
71
|
+
databaseUrl: section.sync.databaseUrl,
|
|
72
|
+
syncMode: section.sync.syncMode || 'interval',
|
|
73
|
+
syncIntervalMs: section.sync.syncIntervalMs || 5 * 60 * 1000,
|
|
74
|
+
} : undefined,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Initialize cache manager
|
|
78
|
+
cacheManager.init().catch(err => {
|
|
79
|
+
console.error('[CelPhoneWeChat] Cache manager init failed:', err);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return cacheManager;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface CelPhoneWeChatResolvedAccount {
|
|
86
|
+
accountId: string | null;
|
|
87
|
+
apiKey: string;
|
|
88
|
+
baseUrl: string;
|
|
89
|
+
wechatAccountId: string; // Required - which WeChat account this is
|
|
90
|
+
wechatId: string; // The actual WeChat ID (wxid_xxx)
|
|
91
|
+
nickName: string; // WeChat nickname for display
|
|
92
|
+
allowFrom: string[];
|
|
93
|
+
dmPolicy: string | undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolve account from OpenClaw config
|
|
98
|
+
*
|
|
99
|
+
* Note: This is a "human account" model - the WeChat account represents
|
|
100
|
+
* a real person with all their friends and groups, not a bot.
|
|
101
|
+
*/
|
|
102
|
+
function resolveAccount(
|
|
103
|
+
cfg: OpenClawConfig,
|
|
104
|
+
accountId?: string | null
|
|
105
|
+
): CelPhoneWeChatResolvedAccount {
|
|
106
|
+
const section = (cfg.channels as Record<string, any>)?.["celphone-wechat"];
|
|
107
|
+
const apiKey = section?.apiKey;
|
|
108
|
+
const baseUrl = section?.baseUrl || "https://api.workphone.example.com";
|
|
109
|
+
const wechatAccountId = section?.wechatAccountId;
|
|
110
|
+
|
|
111
|
+
if (!apiKey) {
|
|
112
|
+
throw new Error("celphone-wechat: apiKey is required");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!wechatAccountId) {
|
|
116
|
+
throw new Error("celphone-wechat: wechatAccountId is required (the WeChat account to use)");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
accountId: accountId ?? null,
|
|
121
|
+
apiKey,
|
|
122
|
+
baseUrl,
|
|
123
|
+
wechatAccountId,
|
|
124
|
+
wechatId: section?.wechatId || wechatAccountId, // Actual WeChat ID (wxid_xxx)
|
|
125
|
+
nickName: section?.nickName || "WeChat User", // Display name
|
|
126
|
+
allowFrom: section?.allowFrom ?? [],
|
|
127
|
+
dmPolicy: section?.dmSecurity,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Create the channel plugin
|
|
133
|
+
*/
|
|
134
|
+
export const celPhoneWeChatPlugin = createChatChannelPlugin<CelPhoneWeChatResolvedAccount>({
|
|
135
|
+
base: createChannelPluginBase({
|
|
136
|
+
id: "celphone-wechat",
|
|
137
|
+
setup: {
|
|
138
|
+
resolveAccount,
|
|
139
|
+
inspectAccount(cfg, accountId) {
|
|
140
|
+
const section = (cfg.channels as Record<string, any>)?.["celphone-wechat"];
|
|
141
|
+
const hasApiKey = Boolean(section?.apiKey);
|
|
142
|
+
return {
|
|
143
|
+
enabled: hasApiKey,
|
|
144
|
+
configured: hasApiKey,
|
|
145
|
+
tokenStatus: hasApiKey ? "available" : "missing",
|
|
146
|
+
};
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
}),
|
|
150
|
+
|
|
151
|
+
// DM security: who can message the bot
|
|
152
|
+
security: {
|
|
153
|
+
dm: {
|
|
154
|
+
channelKey: "celphone-wechat",
|
|
155
|
+
resolvePolicy: (account) => account.dmPolicy,
|
|
156
|
+
resolveAllowFrom: (account) => account.allowFrom,
|
|
157
|
+
defaultPolicy: "allowlist", // Default to allowlist for security
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
// Pairing: not currently supported for this channel
|
|
162
|
+
// WorkPhone WeChat doesn't have a standard pairing flow
|
|
163
|
+
// pairing: { ... },
|
|
164
|
+
|
|
165
|
+
// Threading: how replies are delivered
|
|
166
|
+
// For WeChat, replies go back to the same chat (friend or chatroom)
|
|
167
|
+
threading: {
|
|
168
|
+
topLevelReplyToMode: "reply", // Reply to the last message in the thread
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// Outbound: send messages to WeChat via WorkPhone API
|
|
172
|
+
//
|
|
173
|
+
// HUMAN ACCOUNT MODEL IMPORTANT:
|
|
174
|
+
// This channel connects to a real person's WeChat account.
|
|
175
|
+
// The agent needs to communicate with ALL their friends and groups,
|
|
176
|
+
// not just one conversation. We distinguish by conversation type:
|
|
177
|
+
// - DM (direct): friendWechatId in params.to
|
|
178
|
+
// - Group chat: chatroomId in params.to (detect by format or metadata)
|
|
179
|
+
outbound: {
|
|
180
|
+
attachedResults: {
|
|
181
|
+
// Send text - detect if DM or group based on conversation metadata
|
|
182
|
+
sendText: async (params) => {
|
|
183
|
+
const client = createWorkPhoneClient({
|
|
184
|
+
baseUrl: params.account.baseUrl,
|
|
185
|
+
apiKey: params.account.apiKey,
|
|
186
|
+
accountId: params.account.accountId || undefined,
|
|
187
|
+
wechatAccountId: params.account.wechatAccountId,
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Check if this is a group message (chatroom)
|
|
191
|
+
// Chatroom IDs typically start with certain prefix or have specific format
|
|
192
|
+
const isChatroom = params.metadata?.conversationType === 'group' ||
|
|
193
|
+
(params.to && params.to.includes('@chatroom'));
|
|
194
|
+
|
|
195
|
+
let result;
|
|
196
|
+
if (isChatroom) {
|
|
197
|
+
// Send to chatroom (group)
|
|
198
|
+
result = await client.sendChatroomMessage({
|
|
199
|
+
wechatAccountId: params.account.wechatAccountId,
|
|
200
|
+
chatroomId: params.to,
|
|
201
|
+
content: params.text,
|
|
202
|
+
type: 'text',
|
|
203
|
+
});
|
|
204
|
+
} else {
|
|
205
|
+
// Send to friend (DM)
|
|
206
|
+
result = await client.sendFriendMessage({
|
|
207
|
+
wechatAccountId: params.account.wechatAccountId,
|
|
208
|
+
friendWechatId: params.to,
|
|
209
|
+
content: params.text,
|
|
210
|
+
type: 'text',
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return { messageId: result.messageId };
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
// Send media - also support both DM and group
|
|
218
|
+
sendMedia: async (params) => {
|
|
219
|
+
const client = createWorkPhoneClient({
|
|
220
|
+
baseUrl: params.account.baseUrl,
|
|
221
|
+
apiKey: params.account.apiKey,
|
|
222
|
+
accountId: params.account.accountId || undefined,
|
|
223
|
+
wechatAccountId: params.account.wechatAccountId,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const isChatroom = params.metadata?.conversationType === 'group' ||
|
|
227
|
+
(params.to && params.to.includes('@chatroom'));
|
|
228
|
+
|
|
229
|
+
let result;
|
|
230
|
+
if (isChatroom) {
|
|
231
|
+
result = await client.sendChatroomMessage({
|
|
232
|
+
wechatAccountId: params.account.wechatAccountId,
|
|
233
|
+
chatroomId: params.to,
|
|
234
|
+
content: params.filePath || '',
|
|
235
|
+
type: 'file',
|
|
236
|
+
});
|
|
237
|
+
} else {
|
|
238
|
+
result = await client.sendFriendMessage({
|
|
239
|
+
wechatAccountId: params.account.wechatAccountId,
|
|
240
|
+
friendWechatId: params.to,
|
|
241
|
+
content: params.filePath || '',
|
|
242
|
+
type: 'file',
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return { messageId: result.messageId };
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
// Additional outbound handlers can be added here for:
|
|
251
|
+
// - sendLink: Send link cards
|
|
252
|
+
// - sendLocation: Send location
|
|
253
|
+
// - sendContact: Send contact card
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
// Additional capabilities
|
|
257
|
+
// - Describe the channel's message types and features
|
|
258
|
+
capabilities: {
|
|
259
|
+
supportedMessageTypes: [
|
|
260
|
+
"text",
|
|
261
|
+
"image",
|
|
262
|
+
"video",
|
|
263
|
+
"file",
|
|
264
|
+
"link",
|
|
265
|
+
"location",
|
|
266
|
+
"contact",
|
|
267
|
+
],
|
|
268
|
+
maxAttachmentSize: 25 * 1024 * 1024, // 25MB
|
|
269
|
+
supportsMarkdown: false, // WeChat uses a limited markup
|
|
270
|
+
supportsHtml: false,
|
|
271
|
+
supportsEmoji: true,
|
|
272
|
+
supportsReactions: false, // WeChat doesn't support reactions
|
|
273
|
+
supportsThreads: true, // Can reply in chat
|
|
274
|
+
supportsEditing: false, // Cannot edit sent messages
|
|
275
|
+
supportsDeleting: false, // Cannot delete sent messages
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Helper function to handle inbound webhook messages
|
|
281
|
+
* This should be called from your HTTP route handler
|
|
282
|
+
*
|
|
283
|
+
* Integrates with Cache Manager for:
|
|
284
|
+
* - Local MD file caching
|
|
285
|
+
* - User profile storage
|
|
286
|
+
* - Session memory
|
|
287
|
+
* - Cloud sync
|
|
288
|
+
* - Offline fallback
|
|
289
|
+
*/
|
|
290
|
+
export async function handleInboundMessage(
|
|
291
|
+
api: any,
|
|
292
|
+
payload: WebhookPayload,
|
|
293
|
+
cfg?: OpenClawConfig
|
|
294
|
+
): Promise<void> {
|
|
295
|
+
const { event, accountId, wechatAccountId, message, friendRequest } = payload;
|
|
296
|
+
|
|
297
|
+
if (event === 'message' && message) {
|
|
298
|
+
// Determine conversation type
|
|
299
|
+
const isChatroom = !!(message as any).chatroomId;
|
|
300
|
+
const conversationId = isChatroom
|
|
301
|
+
? (message as any).chatroomId
|
|
302
|
+
: message.fromUser || message.toUser || '';
|
|
303
|
+
|
|
304
|
+
// Convert to cache format and store locally
|
|
305
|
+
if (cacheManager && accountId) {
|
|
306
|
+
try {
|
|
307
|
+
await cacheManager.onMessage({
|
|
308
|
+
messageId: message.messageId,
|
|
309
|
+
msgSvrId: message.msgSvrId,
|
|
310
|
+
accountId: accountId,
|
|
311
|
+
conversationType: isChatroom ? 'chatroom' : 'friend',
|
|
312
|
+
conversationId,
|
|
313
|
+
senderId: message.fromUser || '',
|
|
314
|
+
content: message.content,
|
|
315
|
+
messageType: message.type || 1,
|
|
316
|
+
timestamp: message.timestamp || Date.now(),
|
|
317
|
+
isSelf: message.isSelf || false,
|
|
318
|
+
direction: message.isSelf ? 'outbound' : 'inbound',
|
|
319
|
+
});
|
|
320
|
+
} catch (err) {
|
|
321
|
+
console.error('[CelPhoneWeChat] Cache write failed:', err);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Convert WorkPhone message format to OpenClaw format
|
|
326
|
+
const openclawMessage = {
|
|
327
|
+
id: message.messageId,
|
|
328
|
+
rawId: message.msgSvrId || message.messageId,
|
|
329
|
+
conversation: {
|
|
330
|
+
type: isChatroom ? 'group' as const : 'dm' as const,
|
|
331
|
+
id: conversationId,
|
|
332
|
+
chatroomId: isChatroom ? conversationId : undefined,
|
|
333
|
+
},
|
|
334
|
+
sender: {
|
|
335
|
+
id: message.fromUser || '',
|
|
336
|
+
platformId: message.wechatId,
|
|
337
|
+
},
|
|
338
|
+
content: {
|
|
339
|
+
type: message.type === 1 ? 'text' : 'media',
|
|
340
|
+
text: message.content,
|
|
341
|
+
},
|
|
342
|
+
timestamp: new Date(message.timestamp || Date.now()),
|
|
343
|
+
isSelf: message.isSelf || false,
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// Dispatch to OpenClaw
|
|
347
|
+
await api.inbound.dispatchMessage(openclawMessage);
|
|
348
|
+
} else if (event === 'friend_request' && friendRequest) {
|
|
349
|
+
// Handle friend request
|
|
350
|
+
await api.inbound.dispatchFriendRequest({
|
|
351
|
+
id: friendRequest.v1,
|
|
352
|
+
platformId: friendRequest.fromUser,
|
|
353
|
+
scene: friendRequest.scene,
|
|
354
|
+
ticket: friendRequest.ticket,
|
|
355
|
+
accountId,
|
|
356
|
+
wechatAccountId,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Get user profile from cache (for agent use)
|
|
363
|
+
*/
|
|
364
|
+
export async function getUserProfile(
|
|
365
|
+
accountId: string,
|
|
366
|
+
wechatId: string
|
|
367
|
+
): Promise<any> {
|
|
368
|
+
if (!cacheManager) return null;
|
|
369
|
+
return await cacheManager.getProfile(accountId, wechatId);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Update user profile in cache
|
|
374
|
+
*/
|
|
375
|
+
export async function updateUserProfile(
|
|
376
|
+
accountId: string,
|
|
377
|
+
wechatId: string,
|
|
378
|
+
updates: any
|
|
379
|
+
): Promise<void> {
|
|
380
|
+
if (!cacheManager) return;
|
|
381
|
+
await cacheManager.updateProfile(accountId, wechatId, updates);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Get SAAS connection status
|
|
386
|
+
*/
|
|
387
|
+
export function getConnectionStatus() {
|
|
388
|
+
return cacheManager?.getConnectionStatus();
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Check if system is online (SAAS connected)
|
|
393
|
+
*/
|
|
394
|
+
export function isOnline(): boolean {
|
|
395
|
+
return cacheManager?.isSAASOnline() ?? false;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export default celPhoneWeChatPlugin;
|