openclaw-extension-typex 1.0.19 → 1.0.21

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.
@@ -2,10 +2,37 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TypeXClient = void 0;
4
4
  exports.getTypeXClient = getTypeXClient;
5
+ const domain_js_1 = require("./domain.js");
5
6
  const types_js_1 = require("./types.js");
6
- const TYPEX_DOMAIN = "https://api-coco.typex.im";
7
- // const TYPEX_DOMAIN = "https://api-tx.bossjob.net.cn";
8
7
  let prompter;
8
+ function isSessionAuthFailure(status, bodyText, resJson) {
9
+ const combined = `${bodyText} ${resJson?.msg ?? ""} ${resJson?.message ?? ""}`.toLowerCase();
10
+ return status === 401 || combined.includes("session auth error");
11
+ }
12
+ function summarizeInvalidResponse(status, bodyText) {
13
+ const normalized = bodyText.replace(/\s+/g, " ").trim();
14
+ const htmlTitle = normalized.match(/<title>(.*?)<\/title>/i)?.[1]?.trim();
15
+ const htmlHeading = normalized.match(/<h1>(.*?)<\/h1>/i)?.[1]?.trim();
16
+ const summary = htmlTitle || htmlHeading || normalized.slice(0, 120) || "unexpected response body";
17
+ return `HTTP ${status} - ${summary}`;
18
+ }
19
+ function buildTextContent(content) {
20
+ return typeof content === "string" ? { text: content } : content;
21
+ }
22
+ function escapeHtml(value) {
23
+ return value
24
+ .replace(/&/g, "&amp;")
25
+ .replace(/</g, "&lt;")
26
+ .replace(/>/g, "&gt;")
27
+ .replace(/"/g, "&quot;");
28
+ }
29
+ function buildMentionRichText(text, mentions) {
30
+ const mentionMarkup = mentions
31
+ .map((mention) => `<at userid="${escapeHtml(mention.id)}">${escapeHtml(mention.name)}</at>`)
32
+ .join("&nbsp;");
33
+ const suffix = text.trim() ? `&nbsp;${escapeHtml(text.trim())}` : "";
34
+ return `<p>${mentionMarkup}${suffix}</p>`;
35
+ }
9
36
  class TypeXClient {
10
37
  options;
11
38
  accessToken;
@@ -25,8 +52,41 @@ class TypeXClient {
25
52
  async getCurUserId() {
26
53
  return this.userId ?? "";
27
54
  }
55
+ getAuthHeaders(extraHeaders = {}) {
56
+ if (!this.accessToken) {
57
+ throw new Error("TypeXClient: Not authenticated.");
58
+ }
59
+ return this.mode === "bot"
60
+ ? { Authorization: `Bearer ${this.accessToken}`, ...extraHeaders }
61
+ : { Cookie: this.accessToken, ...extraHeaders };
62
+ }
63
+ async postJson(endpoint, payload) {
64
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}${endpoint}`, {
65
+ method: "POST",
66
+ headers: this.getAuthHeaders({ "Content-Type": "application/json" }),
67
+ body: JSON.stringify(payload),
68
+ });
69
+ const bodyText = await response.text();
70
+ let resJson;
71
+ try {
72
+ resJson = JSON.parse(bodyText);
73
+ }
74
+ catch {
75
+ if (isSessionAuthFailure(response.status, bodyText)) {
76
+ throw new Error("TypeX 用户登录态已失效,请在 OpenClaw 中重新扫码登录 TypeX user 账号后再试。");
77
+ }
78
+ throw new Error(`TypeX API ${endpoint} returned invalid JSON: ${summarizeInvalidResponse(response.status, bodyText)}`);
79
+ }
80
+ if (!response.ok || resJson.code !== 0) {
81
+ if (isSessionAuthFailure(response.status, bodyText, resJson)) {
82
+ throw new Error("TypeX 用户登录态已失效,请在 OpenClaw 中重新扫码登录 TypeX user 账号后再试。");
83
+ }
84
+ throw new Error(`TypeX API ${endpoint} failed: [${resJson.code ?? response.status}] ${resJson.msg || resJson.message || "unknown error"}`);
85
+ }
86
+ return (resJson.data ?? []);
87
+ }
28
88
  async fetchQrcodeUrl() {
29
- const qrResponse = await fetch(`${TYPEX_DOMAIN}/user/qrcode?login_type=open`, {
89
+ const qrResponse = await fetch(`${domain_js_1.TYPEX_DOMAIN}/user/qrcode?login_type=open`, {
30
90
  method: "POST",
31
91
  headers: { "Content-Type": "application/json" },
32
92
  body: JSON.stringify({}),
@@ -41,7 +101,7 @@ class TypeXClient {
41
101
  return qrResult.data;
42
102
  }
43
103
  async checkLoginStatus(qrcodeId) {
44
- const checkRes = await fetch(`${TYPEX_DOMAIN}/open/qrcode/check_auth`, {
104
+ const checkRes = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/qrcode/check_auth`, {
45
105
  method: "POST",
46
106
  headers: { "Content-Type": "application/json" },
47
107
  body: JSON.stringify({ qr_code_id: qrcodeId }),
@@ -59,66 +119,15 @@ class TypeXClient {
59
119
  }
60
120
  return false;
61
121
  }
62
- /**
63
- * Send a message to a specific chat (group or DM).
64
- * @param to chat_id to send to
65
- * @param content message text or object
66
- */
67
- async sendMessage(to, content, msgType = 0, options = {}) {
68
- const token = this.accessToken;
69
- if (!token)
122
+ async executeSendMessage(endpoint, to, payload, preview) {
123
+ if (!this.accessToken)
70
124
  throw new Error("TypeXClient: Not authenticated.");
71
- let finalContent = content;
72
- if (typeof content === "object") {
73
- try {
74
- finalContent = JSON.stringify(content);
75
- }
76
- catch {
77
- finalContent = String(content);
78
- }
79
- }
80
125
  if (prompter)
81
- prompter.note(`TypeXClient sending to ${to}: ${String(finalContent).slice(0, 80)}`);
82
- else
83
- console.log(`TypeXClient sending to ${to}: ${String(finalContent).slice(0, 80)}`);
84
- const isBot = this.mode === "bot";
85
- const endpoint = isBot ? "/open/robot/send_message" : "/open/claw/send_message";
86
- let payloadStr;
87
- if (isBot) {
88
- let botContentObj;
89
- if (msgType === types_js_1.TypeXMessageEnum.text || msgType === types_js_1.TypeXMessageEnum.richText) {
90
- // According to docs, text type content format: {"text":"test"}
91
- // Assuming content or finalContent holds the actual string text.
92
- botContentObj = {
93
- text: typeof content === "string" ? content : (typeof finalContent === "string" ? finalContent : JSON.stringify(content))
94
- };
95
- // Ensure msgType is 0 when sending to `/open/robot/send_message` since 8 might not be supported natively by robot API
96
- msgType = types_js_1.TypeXMessageEnum.text;
97
- }
98
- else {
99
- // Image or File object payload for bot
100
- botContentObj = typeof finalContent === "string" ? { text: finalContent } : content;
101
- }
102
- payloadStr = JSON.stringify({
103
- chat_id: to,
104
- content: botContentObj,
105
- msg_type: msgType,
106
- reply_msg_id: options.replyMsgId || "0",
107
- });
108
- }
109
- else {
110
- payloadStr = JSON.stringify({
111
- chat_id: to,
112
- content: { text: finalContent },
113
- msg_type: msgType,
114
- });
115
- }
116
- const response = await fetch(`${TYPEX_DOMAIN}${endpoint}`, {
126
+ prompter.note(`TypeXClient sending to ${to}: ${preview.slice(0, 80)}`);
127
+ const payloadStr = JSON.stringify(payload);
128
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}${endpoint}`, {
117
129
  method: "POST",
118
- headers: {
119
- "Content-Type": "application/json",
120
- ...(isBot ? { Authorization: `Bearer ${token}` } : { Cookie: token }),
121
- },
130
+ headers: this.getAuthHeaders({ "Content-Type": "application/json" }),
122
131
  body: payloadStr,
123
132
  });
124
133
  const bodyText = await response.text();
@@ -127,13 +136,104 @@ class TypeXClient {
127
136
  resJson = JSON.parse(bodyText);
128
137
  }
129
138
  catch (e) {
130
- throw new Error(`Send message failed (invalid JSON): HTTP ${response.status} - ${bodyText}`);
139
+ if (isSessionAuthFailure(response.status, bodyText)) {
140
+ throw new Error("TypeX 用户登录态已失效,请在 OpenClaw 中重新扫码登录 TypeX user 账号后再试。");
141
+ }
142
+ throw new Error(`Send message failed (invalid JSON): ${summarizeInvalidResponse(response.status, bodyText)}`);
131
143
  }
132
144
  if (resJson.code !== 0) {
145
+ if (isSessionAuthFailure(response.status, bodyText, resJson)) {
146
+ throw new Error("TypeX 用户登录态已失效,请在 OpenClaw 中重新扫码登录 TypeX user 账号后再试。");
147
+ }
133
148
  throw new Error(`Send message failed: [${resJson.code}] ${resJson.msg || resJson.message}`);
134
149
  }
135
150
  return resJson.data || { message_id: `msg_${Date.now()}` };
136
151
  }
152
+ async sendUserChatMessage(chatId, content, msgType = types_js_1.TypeXMessageEnum.text) {
153
+ return this.executeSendMessage("/open/claw/send_message", chatId, {
154
+ chat_id: chatId,
155
+ content: buildTextContent(content),
156
+ msg_type: msgType,
157
+ }, typeof content === "string" ? content : JSON.stringify(content));
158
+ }
159
+ async sendDelegatedChatMessage(chatId, content, msgType = types_js_1.TypeXMessageEnum.text) {
160
+ return this.executeSendMessage("/open/claw/send_message", chatId, {
161
+ chat_id: chatId,
162
+ content: buildTextContent(content),
163
+ msg_type: msgType,
164
+ is_delegate: true,
165
+ }, typeof content === "string" ? content : JSON.stringify(content));
166
+ }
167
+ async sendDelegatedContactMessage(receiverId, content, msgType = types_js_1.TypeXMessageEnum.text) {
168
+ return this.executeSendMessage("/open/claw/send_message", receiverId, {
169
+ receiver_id: receiverId,
170
+ content: buildTextContent(content),
171
+ msg_type: msgType,
172
+ is_delegate: true,
173
+ }, typeof content === "string" ? content : JSON.stringify(content));
174
+ }
175
+ async sendBotGroupMessage(chatId, content, msgType = types_js_1.TypeXMessageEnum.text, options = {}) {
176
+ const mentionIds = Array.isArray(options.atUserIds) && options.atUserIds.length > 0 ? options.atUserIds : undefined;
177
+ const mentionEntries = Array.isArray(options.atMentions) && options.atMentions.length > 0 ? options.atMentions : undefined;
178
+ const normalizedMsgType = msgType === types_js_1.TypeXMessageEnum.text || msgType === types_js_1.TypeXMessageEnum.richText
179
+ ? types_js_1.TypeXMessageEnum.text
180
+ : msgType;
181
+ const normalizedContent = normalizedMsgType === types_js_1.TypeXMessageEnum.text
182
+ ? {
183
+ text: mentionEntries && mentionEntries.length > 0
184
+ ? buildMentionRichText(typeof content === "string" ? content : JSON.stringify(content), mentionEntries)
185
+ : typeof content === "string"
186
+ ? content
187
+ : JSON.stringify(content),
188
+ at_user_ids: mentionIds,
189
+ }
190
+ : typeof content === "object" && content !== null
191
+ ? {
192
+ ...content,
193
+ at_user_ids: mentionIds,
194
+ }
195
+ : content;
196
+ return this.executeSendMessage("/open/robot/send_message", chatId, {
197
+ chat_id: chatId,
198
+ content: normalizedContent,
199
+ msg_type: normalizedMsgType,
200
+ reply_msg_id: options.replyMsgId || "0",
201
+ }, typeof content === "string" ? content : JSON.stringify(content));
202
+ }
203
+ /**
204
+ * Compatibility wrapper. Prefer the explicit methods above for new call sites.
205
+ */
206
+ async sendMessage(to, content, msgType = types_js_1.TypeXMessageEnum.text, options = {}) {
207
+ if (this.mode === "bot") {
208
+ return this.sendBotGroupMessage(to, content, msgType, {
209
+ replyMsgId: options.replyMsgId,
210
+ atUserIds: options.atUserIds,
211
+ atMentions: options.atMentions,
212
+ });
213
+ }
214
+ if (options.isDelegate && options.receiverId) {
215
+ return this.sendDelegatedContactMessage(options.receiverId, content, msgType);
216
+ }
217
+ if (options.isDelegate) {
218
+ return this.sendDelegatedChatMessage(to, content, msgType);
219
+ }
220
+ return this.sendUserChatMessage(to, content, msgType);
221
+ }
222
+ async searchFeedsByName(name) {
223
+ if (!name.trim())
224
+ return [];
225
+ return this.postJson("/open/claw/feeds_by_name", { name });
226
+ }
227
+ async searchContactsByName(name) {
228
+ if (!name.trim())
229
+ return [];
230
+ return this.postJson("/open/claw/contacts_by_name", { name });
231
+ }
232
+ async listGroupMembers(chatId) {
233
+ if (!chatId.trim() || this.mode !== "bot")
234
+ return [];
235
+ return this.postJson("/open/robot/group_members", { chatid: chatId });
236
+ }
137
237
  /**
138
238
  * Upload resource for the robot to send.
139
239
  * @param fileName Name of the file
@@ -154,10 +254,10 @@ class TypeXClient {
154
254
  // By providing a Blob we ensure it correctly adds boundaries and content types per form part.
155
255
  const blob = fileContent instanceof Buffer ? new Blob([fileContent]) : fileContent;
156
256
  formData.append("file_content", blob, fileName);
157
- const response = await fetch(`${TYPEX_DOMAIN}/open/robot/upload`, {
257
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/robot/upload`, {
158
258
  method: "POST",
159
259
  headers: {
160
- Authorization: `Bearer ${this.accessToken}`
260
+ Authorization: `Bearer ${this.accessToken}`,
161
261
  // Note: fetch will automatically set the Content-Type boundary
162
262
  },
163
263
  body: formData,
@@ -168,6 +268,42 @@ class TypeXClient {
168
268
  }
169
269
  return resJson.data;
170
270
  }
271
+ async uploadUserResource(fileName, fileType, fileContent, chatId) {
272
+ if (this.mode !== "user" || !this.accessToken) {
273
+ throw new Error("TypeXClient: uploadUserResource requires user mode and a session token.");
274
+ }
275
+ const formData = new FormData();
276
+ formData.append("chat_id", chatId);
277
+ formData.append("file_name", fileName);
278
+ formData.append("file_type", fileType);
279
+ const blob = fileContent instanceof Buffer ? new Blob([fileContent]) : fileContent;
280
+ formData.append("file_content", blob, fileName);
281
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/upload`, {
282
+ method: "POST",
283
+ headers: {
284
+ Cookie: this.accessToken,
285
+ },
286
+ body: formData,
287
+ });
288
+ const bodyText = await response.text();
289
+ let resJson;
290
+ try {
291
+ resJson = JSON.parse(bodyText);
292
+ }
293
+ catch {
294
+ if (isSessionAuthFailure(response.status, bodyText)) {
295
+ throw new Error("TypeX 用户登录态已失效,请在 OpenClaw 中重新扫码登录 TypeX user 账号后再试。");
296
+ }
297
+ throw new Error(`Upload user resource failed (invalid JSON): ${summarizeInvalidResponse(response.status, bodyText)}`);
298
+ }
299
+ if (!response.ok || resJson.code !== 0) {
300
+ if (isSessionAuthFailure(response.status, bodyText, resJson)) {
301
+ throw new Error("TypeX 用户登录态已失效,请在 OpenClaw 中重新扫码登录 TypeX user 账号后再试。");
302
+ }
303
+ throw new Error(`Upload user resource failed: [${resJson.code ?? response.status}] ${resJson.msg || resJson.message || "unknown error"}`);
304
+ }
305
+ return resJson.data;
306
+ }
171
307
  /**
172
308
  * Fetch messages. Dispatches to user or bot endpoint based on mode.
173
309
  */
@@ -180,64 +316,47 @@ class TypeXClient {
180
316
  async fetchUserMessages(pos) {
181
317
  if (!this.accessToken)
182
318
  return [];
319
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/claw/message`, {
320
+ method: "POST",
321
+ headers: { Cookie: this.accessToken, "Content-Type": "application/json" },
322
+ body: JSON.stringify({ pos }),
323
+ });
324
+ const bodyText = await response.text();
325
+ let resJson;
183
326
  try {
184
- const response = await fetch(`${TYPEX_DOMAIN}/open/claw/message`, {
185
- method: "POST",
186
- headers: { Cookie: this.accessToken, "Content-Type": "application/json" },
187
- body: JSON.stringify({ pos }),
188
- });
189
- if (response.status === 401) {
190
- throw new Error("Unauthorized: 401 Token is invalid or expired.");
191
- }
192
- if (!response.ok) {
193
- throw new Error(`HTTP Error: ${response.status}`);
194
- }
195
- const resJson = await response.json();
196
- if (resJson.code !== 0) {
197
- throw new Error(`API Error: code ${resJson.code}, message: ${resJson.msg}`);
198
- }
199
- return Array.isArray(resJson.data) ? resJson.data : [];
327
+ resJson = JSON.parse(bodyText);
200
328
  }
201
- catch (e) {
202
- if (e instanceof Error && e.message.includes("Unauthorized")) {
203
- throw e;
204
- }
205
- console.log(`Fetch messages error: ${e}`);
206
- return [];
329
+ catch {
330
+ throw new Error(`TypeX user poll returned non-JSON response: ${summarizeInvalidResponse(response.status, bodyText)}`);
207
331
  }
332
+ if (!response.ok || resJson.code !== 0) {
333
+ throw new Error(`TypeX user poll failed: HTTP ${response.status} - ${resJson.msg || resJson.message || "unknown error"}`);
334
+ }
335
+ return Array.isArray(resJson.data) ? resJson.data : [];
208
336
  }
209
337
  /**
210
338
  * Pull messages for a bot account (Bearer token auth).
211
- * TODO: replace /open/bot/message with the actual endpoint path once confirmed.
212
339
  */
213
340
  async fetchBotMessages() {
214
341
  if (!this.accessToken)
215
342
  return [];
343
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/robot/message/pull`, {
344
+ method: "POST",
345
+ headers: { Authorization: `Bearer ${this.accessToken}`, "Content-Type": "application/json" },
346
+ body: JSON.stringify({ limit: 5 }),
347
+ });
348
+ const bodyText = await response.text();
349
+ let resJson;
216
350
  try {
217
- const response = await fetch(`${TYPEX_DOMAIN}/open/robot/message/pull`, {
218
- method: "POST",
219
- headers: { Authorization: `Bearer ${this.accessToken}`, "Content-Type": "application/json" },
220
- body: JSON.stringify({ limit: 5 }),
221
- });
222
- if (response.status === 401) {
223
- throw new Error("Unauthorized: 401 Bot Token is invalid or expired.");
224
- }
225
- if (!response.ok) {
226
- throw new Error(`HTTP Error: ${response.status}`);
227
- }
228
- const resJson = await response.json();
229
- if (resJson.code !== 0) {
230
- return [];
231
- }
232
- return Array.isArray(resJson.data?.messages) ? resJson.data.messages : [];
351
+ resJson = JSON.parse(bodyText);
233
352
  }
234
- catch (e) {
235
- if (e instanceof Error && e.message.includes("Unauthorized")) {
236
- throw e;
237
- }
238
- console.log(`Bot fetch messages error: ${e}`);
239
- return [];
353
+ catch {
354
+ throw new Error(`TypeX bot poll returned non-JSON response: ${summarizeInvalidResponse(response.status, bodyText)}`);
355
+ }
356
+ if (!response.ok || resJson.code !== 0) {
357
+ throw new Error(`TypeX bot poll failed: HTTP ${response.status} - ${resJson.msg || resJson.message || "unknown error"}`);
240
358
  }
359
+ return Array.isArray(resJson.data?.messages) ? resJson.data.messages : [];
241
360
  }
242
361
  /**
243
362
  * Fetch a single message by ID (used to resolve quoted/parent messages).
@@ -247,7 +366,7 @@ class TypeXClient {
247
366
  return null;
248
367
  try {
249
368
  const isBot = this.mode === "bot";
250
- const response = await fetch(`${TYPEX_DOMAIN}/open/claw/message/${messageId}`, {
369
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/claw/message/${messageId}`, {
251
370
  method: "GET",
252
371
  headers: isBot
253
372
  ? { Authorization: `Bearer ${this.accessToken}`, "Content-Type": "application/json" }
@@ -265,19 +384,22 @@ class TypeXClient {
265
384
  * Requires Bot Token authentication.
266
385
  */
267
386
  async fetchFileBuffer(objectKey, size) {
268
- if (!this.accessToken || this.mode !== "bot")
387
+ if (!this.accessToken)
269
388
  return null;
270
389
  try {
271
390
  const query = new URLSearchParams({ object_key: objectKey });
272
391
  if (size)
273
392
  query.append("size", size);
274
- const url = `${TYPEX_DOMAIN}/open/robot/chat/file?${query.toString()}`;
393
+ const isBot = this.mode === "bot";
394
+ const url = isBot
395
+ ? `${domain_js_1.TYPEX_DOMAIN}/open/robot/chat/file?${query.toString()}`
396
+ : `${domain_js_1.TYPEX_DOMAIN}/open/file?${query.toString()}`;
275
397
  const response = await fetch(url, {
276
398
  method: "GET",
277
- headers: { Authorization: `Bearer ${this.accessToken}` },
399
+ headers: this.getAuthHeaders(),
278
400
  });
279
401
  if (!response.ok) {
280
- console.log(`fetchFileBuffer failed with status: ${response.status} ${response.statusText} for url: ${url}`);
402
+ console.warn(`fetchFileBuffer failed with status: ${response.status} ${response.statusText} for url: ${url}`);
281
403
  return null;
282
404
  }
283
405
  const arrayBuffer = await response.arrayBuffer();
@@ -286,10 +408,76 @@ class TypeXClient {
286
408
  return { buffer, mimeType };
287
409
  }
288
410
  catch (e) {
289
- console.log(`fetchFileBuffer error: ${e}`);
411
+ console.error(`fetchFileBuffer error: ${e}`);
290
412
  return null;
291
413
  }
292
414
  }
415
+ /**
416
+ * Search feeds by name (User mode)
417
+ */
418
+ async fetchFeedsByName(name) {
419
+ if (!this.accessToken || this.mode !== "user")
420
+ return [];
421
+ try {
422
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/claw/feeds_by_name`, {
423
+ method: "POST",
424
+ headers: { Cookie: this.accessToken, "Content-Type": "application/json" },
425
+ body: JSON.stringify({ name }),
426
+ });
427
+ const resJson = await response.json();
428
+ if (resJson.code !== 0)
429
+ return [];
430
+ return Array.isArray(resJson.data) ? resJson.data : [];
431
+ }
432
+ catch (e) {
433
+ console.error(`fetchFeedsByName error: ${e}`);
434
+ return [];
435
+ }
436
+ }
437
+ /**
438
+ * Search contacts by name (User mode)
439
+ */
440
+ async fetchContactsByName(name) {
441
+ if (!this.accessToken || this.mode !== "user")
442
+ return [];
443
+ try {
444
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/claw/contacts_by_name`, {
445
+ method: "POST",
446
+ headers: { Cookie: this.accessToken, "Content-Type": "application/json" },
447
+ body: JSON.stringify({ name }),
448
+ });
449
+ const resJson = await response.json();
450
+ if (resJson.code !== 0)
451
+ return [];
452
+ return Array.isArray(resJson.data) ? resJson.data : [];
453
+ }
454
+ catch (e) {
455
+ console.error(`fetchContactsByName error: ${e}`);
456
+ return [];
457
+ }
458
+ }
459
+ /**
460
+ * Search group members by name (Bot mode)
461
+ */
462
+ async fetchGroupMembersByName(name) {
463
+ if (!this.accessToken || this.mode !== "bot")
464
+ return [];
465
+ try {
466
+ const response = await fetch(`${domain_js_1.TYPEX_DOMAIN}/open/claw/group_members`, {
467
+ method: "POST",
468
+ headers: { Authorization: `Bearer ${this.accessToken}`, "Content-Type": "application/json" },
469
+ body: JSON.stringify({ name }),
470
+ });
471
+ const resJson = await response.json();
472
+ if (resJson.code !== 0)
473
+ return [];
474
+ return Array.isArray(resJson.data) ? resJson.data : [];
475
+ }
476
+ catch (e) {
477
+ console.error(`fetchGroupMembersByName error: ${e}`);
478
+ return [];
479
+ }
480
+ }
293
481
  }
294
482
  exports.TypeXClient = TypeXClient;
295
483
  function getTypeXClient(accountId, manualOptions) {
@@ -1,5 +1,6 @@
1
- import type { OpenClawConfig, DmPolicy, GroupPolicy } from "openclaw/plugin-sdk";
2
- import type { TypeXGroupConfig } from "../types";
1
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/channel-core";
2
+ import type { DmPolicy, GroupPolicy } from "openclaw/plugin-sdk/setup";
3
+ import type { TypeXGroupConfig } from "../types.js";
3
4
  export type ResolvedTypeXConfig = {
4
5
  enabled: boolean;
5
6
  dmPolicy: DmPolicy;
@@ -0,0 +1,7 @@
1
+ export declare const TYPEX_DOMAINS: {
2
+ readonly prod: "https://api-coco.typex.im";
3
+ readonly test: "https://api-tx.typex-test.cn";
4
+ };
5
+ export type TypeXDomainTarget = keyof typeof TYPEX_DOMAINS;
6
+ export declare const ACTIVE_TYPEX_DOMAIN_TARGET: TypeXDomainTarget;
7
+ export declare const TYPEX_DOMAIN: "https://api-coco.typex.im";
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TYPEX_DOMAIN = exports.ACTIVE_TYPEX_DOMAIN_TARGET = exports.TYPEX_DOMAINS = void 0;
4
+ exports.TYPEX_DOMAINS = {
5
+ prod: "https://api-coco.typex.im",
6
+ test: "https://api-tx.typex-test.cn",
7
+ };
8
+ exports.ACTIVE_TYPEX_DOMAIN_TARGET = "prod";
9
+ exports.TYPEX_DOMAIN = exports.TYPEX_DOMAINS[exports.ACTIVE_TYPEX_DOMAIN_TARGET];
@@ -4,7 +4,8 @@
4
4
  * Main message dispatch orchestrator for the TypeX standalone plugin.
5
5
  * Pure helpers live in ./message-helpers.ts.
6
6
  */
7
- import type { HistoryEntry, OpenClawConfig } from "openclaw/plugin-sdk";
7
+ import type { OpenClawConfig } from "openclaw/plugin-sdk/channel-core";
8
+ import { type HistoryEntry } from "openclaw/plugin-sdk/reply-history";
8
9
  import type { TypeXClient } from "./client.js";
9
10
  import { type TypeXMessageEntry } from "./types.js";
10
11
  export type ProcessTypeXMessageOptions = {