@zhin.js/adapter-telegram 5.0.1 → 5.0.3

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +65 -139
  3. package/adapters/telegram.ts +27 -0
  4. package/agent/tools/create_invite.ts +20 -0
  5. package/agent/tools/list_admins.ts +26 -0
  6. package/agent/tools/member_count.ts +18 -0
  7. package/agent/tools/pin_message.ts +21 -0
  8. package/agent/tools/react.ts +20 -0
  9. package/agent/tools/send_poll.ts +34 -0
  10. package/agent/tools/send_sticker.ts +19 -0
  11. package/agent/tools/set_description.ts +19 -0
  12. package/agent/tools/set_permissions.ts +33 -0
  13. package/agent/tools/unpin_message.ts +21 -0
  14. package/lib/endpoint.d.ts +58 -148
  15. package/lib/endpoint.js +273 -987
  16. package/lib/index.d.ts +4 -18
  17. package/lib/index.js +4 -462
  18. package/lib/platform-permit.d.ts +1 -2
  19. package/lib/platform-permit.js +4 -2
  20. package/lib/polling.d.ts +9 -0
  21. package/lib/polling.js +52 -0
  22. package/lib/protocol.d.ts +250 -0
  23. package/lib/protocol.js +324 -0
  24. package/lib/telegram-agent-deps.d.ts +28 -0
  25. package/lib/telegram-agent-deps.js +30 -0
  26. package/lib/webhook.d.ts +13 -0
  27. package/lib/webhook.js +45 -0
  28. package/package.json +46 -33
  29. package/plugin.ts +13 -0
  30. package/schema.json +39 -0
  31. package/src/endpoint.ts +339 -1103
  32. package/src/index.ts +39 -435
  33. package/src/platform-permit.ts +1 -2
  34. package/src/polling.ts +71 -0
  35. package/src/protocol.ts +573 -0
  36. package/src/telegram-agent-deps.ts +63 -0
  37. package/src/webhook.ts +67 -0
  38. package/client/Dashboard.tsx +0 -295
  39. package/client/index.tsx +0 -11
  40. package/client/tsconfig.json +0 -7
  41. package/client/utils/api.ts +0 -30
  42. package/dist/index.js +0 -32
  43. package/lib/adapter.d.ts +0 -21
  44. package/lib/adapter.d.ts.map +0 -1
  45. package/lib/adapter.js +0 -58
  46. package/lib/adapter.js.map +0 -1
  47. package/lib/endpoint.d.ts.map +0 -1
  48. package/lib/endpoint.js.map +0 -1
  49. package/lib/index.d.ts.map +0 -1
  50. package/lib/index.js.map +0 -1
  51. package/lib/platform-permit.d.ts.map +0 -1
  52. package/lib/platform-permit.js.map +0 -1
  53. package/lib/segment-mapper.d.ts +0 -2
  54. package/lib/segment-mapper.d.ts.map +0 -1
  55. package/lib/segment-mapper.js +0 -2
  56. package/lib/segment-mapper.js.map +0 -1
  57. package/lib/types.d.ts +0 -29
  58. package/lib/types.d.ts.map +0 -1
  59. package/lib/types.js +0 -2
  60. package/lib/types.js.map +0 -1
  61. package/plugin.yml +0 -3
  62. package/src/adapter.ts +0 -66
  63. package/src/segment-mapper.ts +0 -1
  64. package/src/types.ts +0 -32
  65. /package/{skills/telegram → agent}/PERMITS.md +0 -0
  66. /package/{skills/telegram/SKILL.md → agent/skills/telegram.md} +0 -0
package/lib/index.d.ts CHANGED
@@ -1,18 +1,4 @@
1
- import { TelegramAdapter } from "./adapter.js";
2
- import { PageManager } from "@zhin.js/host-api";
3
- declare module "zhin.js" {
4
- namespace Plugin {
5
- interface Contexts {
6
- web: PageManager;
7
- }
8
- }
9
- }
10
- declare module "zhin.js" {
11
- interface Adapters {
12
- telegram: TelegramAdapter;
13
- }
14
- }
15
- export * from "./types.js";
16
- export { TelegramEndpoint } from "./endpoint.js";
17
- export { TelegramAdapter } from "./adapter.js";
18
- //# sourceMappingURL=index.d.ts.map
1
+ export { TelegramEndpoint, type TelegramEndpointOptions, type TelegramFetch, } from './endpoint.js';
2
+ export { botApiUrl, formatCallbackContent, formatInboundContent, formatOutboundActions, normalizeWebhookPath, resolveChannel, resolveTelegramConfig, senderDisplayName, type ResolvedTelegramConfig, type TelegramAdapterConfig, type TelegramCallbackQuery, type TelegramChat, type TelegramChatMember, type TelegramMessage, type TelegramOutboundAction, type TelegramUpdate, type TelegramUser, type TelegramWireSegment, } from './protocol.js';
3
+ export { getTelegramAgentDeps, registerTelegramAgentEndpoint, setTelegramAgentDeps, type TelegramAgentDeps, type TelegramAgentEndpoint, } from './telegram-agent-deps.js';
4
+ export { checkTelegramPlatformPermit, normalizeTelegramChatMember, platformPermit, registerTelegramPlatformPermitChecker, telegramGroupPermitResolver, } from './platform-permit.js';
package/lib/index.js CHANGED
@@ -1,462 +1,4 @@
1
- /**
2
- * Telegram 适配器入口:类型扩展、导出、注册
3
- */
4
- import path from "node:path";
5
- import { usePlugin, createSceneManagementTools } from "zhin.js";
6
- import { TelegramAdapter } from "./adapter.js";
7
- import { platformPermit, registerTelegramPlatformPermitChecker, telegramGroupPermitResolver, } from "./platform-permit.js";
8
- export * from "./types.js";
9
- export { TelegramEndpoint } from "./endpoint.js";
10
- export { TelegramAdapter } from "./adapter.js";
11
- const plugin = usePlugin();
12
- const { provide, useContext } = plugin;
13
- provide({
14
- name: "telegram",
15
- description: "Telegram Endpoint Adapter",
16
- mounted: async (p) => {
17
- const adapter = new TelegramAdapter(p);
18
- await adapter.start();
19
- return adapter;
20
- },
21
- dispose: async (adapter) => {
22
- await adapter.stop();
23
- },
24
- });
25
- useContext('tool', 'telegram', (toolService, telegram) => {
26
- const disposers = [];
27
- disposers.push(registerTelegramPlatformPermitChecker());
28
- const sceneTools = createSceneManagementTools(telegram, 'telegram', { permitResolver: telegramGroupPermitResolver, registerChecker: false });
29
- disposers.push(...sceneTools.map(t => toolService.addTool(t, plugin.name)));
30
- disposers.push(toolService.addTool({
31
- name: 'telegram_pin_message',
32
- description: '置顶 Telegram 群组消息',
33
- parameters: {
34
- type: 'object',
35
- properties: {
36
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
37
- chat_id: { type: 'string', description: '聊天 ID' },
38
- message_id: { type: 'string', description: '消息 ID' },
39
- },
40
- required: ['endpoint_id', 'chat_id', 'message_id'],
41
- },
42
- platforms: ['telegram'],
43
- tags: ['telegram'],
44
- permissions: [platformPermit('pin_messages')],
45
- execute: async (args) => {
46
- const endpoint = telegram.endpoints.get(args.endpoint_id);
47
- if (!endpoint)
48
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
49
- const success = await endpoint.pinMessage(Number(args.chat_id), Number(args.message_id));
50
- return { success, message: success ? '消息已置顶' : '操作失败' };
51
- },
52
- }, plugin.name));
53
- disposers.push(toolService.addTool({
54
- name: 'telegram_unpin_message',
55
- description: '取消置顶 Telegram 群组消息',
56
- parameters: {
57
- type: 'object',
58
- properties: {
59
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
60
- chat_id: { type: 'string', description: '聊天 ID' },
61
- message_id: { type: 'string', description: '消息 ID(可选,不提供则取消所有置顶)' },
62
- },
63
- required: ['endpoint_id', 'chat_id'],
64
- },
65
- platforms: ['telegram'],
66
- tags: ['telegram'],
67
- permissions: [platformPermit('pin_messages')],
68
- execute: async (args) => {
69
- const endpoint = telegram.endpoints.get(args.endpoint_id);
70
- if (!endpoint)
71
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
72
- const success = await endpoint.unpinMessage(Number(args.chat_id), args.message_id ? Number(args.message_id) : undefined);
73
- return { success, message: success ? '已取消置顶' : '操作失败' };
74
- },
75
- }, plugin.name));
76
- disposers.push(toolService.addTool({
77
- name: 'telegram_list_admins',
78
- description: '获取 Telegram 群组管理员列表',
79
- parameters: {
80
- type: 'object',
81
- properties: {
82
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
83
- chat_id: { type: 'string', description: '聊天 ID' },
84
- },
85
- required: ['endpoint_id', 'chat_id'],
86
- },
87
- platforms: ['telegram'],
88
- tags: ['telegram'],
89
- execute: async (args) => {
90
- const endpoint = telegram.endpoints.get(args.endpoint_id);
91
- if (!endpoint)
92
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
93
- const admins = await endpoint.getChatAdmins(Number(args.chat_id));
94
- return {
95
- admins: admins.map((a) => ({
96
- user_id: a.user.id,
97
- username: a.user.username,
98
- first_name: a.user.first_name,
99
- status: a.status,
100
- })),
101
- count: admins.length,
102
- };
103
- },
104
- }, plugin.name));
105
- disposers.push(toolService.addTool({
106
- name: 'telegram_member_count',
107
- description: '获取 Telegram 群组成员数量',
108
- parameters: {
109
- type: 'object',
110
- properties: {
111
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
112
- chat_id: { type: 'string', description: '聊天 ID' },
113
- },
114
- required: ['endpoint_id', 'chat_id'],
115
- },
116
- platforms: ['telegram'],
117
- tags: ['telegram'],
118
- execute: async (args) => {
119
- const endpoint = telegram.endpoints.get(args.endpoint_id);
120
- if (!endpoint)
121
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
122
- const count = await endpoint.getChatMemberCount(Number(args.chat_id));
123
- return { count, message: `群组共有 ${count} 名成员` };
124
- },
125
- }, plugin.name));
126
- disposers.push(toolService.addTool({
127
- name: 'telegram_create_invite',
128
- description: '创建 Telegram 群组邀请链接',
129
- parameters: {
130
- type: 'object',
131
- properties: {
132
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
133
- chat_id: { type: 'string', description: '聊天 ID' },
134
- },
135
- required: ['endpoint_id', 'chat_id'],
136
- },
137
- platforms: ['telegram'],
138
- tags: ['telegram'],
139
- permissions: [platformPermit('chat_administrator')],
140
- execute: async (args) => {
141
- const endpoint = telegram.endpoints.get(args.endpoint_id);
142
- if (!endpoint)
143
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
144
- const link = await endpoint.createInviteLink(Number(args.chat_id));
145
- return { invite_link: link, message: `邀请链接: ${link}` };
146
- },
147
- }, plugin.name));
148
- disposers.push(toolService.addTool({
149
- name: 'telegram_send_poll',
150
- description: '在 Telegram 群组中发起投票',
151
- parameters: {
152
- type: 'object',
153
- properties: {
154
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
155
- chat_id: { type: 'string', description: '聊天 ID' },
156
- question: { type: 'string', description: '投票问题' },
157
- options: { type: 'string', description: '选项 JSON 数组,如 ["A","B","C"]' },
158
- is_anonymous: { type: 'boolean', description: '是否匿名投票,默认 true' },
159
- allows_multiple: { type: 'boolean', description: '是否允许多选,默认 false' },
160
- },
161
- required: ['endpoint_id', 'chat_id', 'question', 'options'],
162
- },
163
- platforms: ['telegram'],
164
- tags: ['telegram'],
165
- execute: async (args) => {
166
- const endpoint = telegram.endpoints.get(args.endpoint_id);
167
- if (!endpoint)
168
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
169
- let optList;
170
- try {
171
- optList = JSON.parse(args.options);
172
- }
173
- catch {
174
- return { success: false, message: 'options 格式错误,应为 JSON 数组' };
175
- }
176
- if (!Array.isArray(optList) || optList.length < 2) {
177
- return { success: false, message: '至少需要 2 个选项' };
178
- }
179
- const result = await endpoint.sendPoll(Number(args.chat_id), args.question, optList, args.is_anonymous ?? true, args.allows_multiple ?? false);
180
- return { success: true, message_id: result.message_id, message: '投票已发送' };
181
- },
182
- }, plugin.name));
183
- disposers.push(toolService.addTool({
184
- name: 'telegram_react',
185
- description: '对 Telegram 消息添加表情反应',
186
- parameters: {
187
- type: 'object',
188
- properties: {
189
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
190
- chat_id: { type: 'string', description: '聊天 ID' },
191
- message_id: { type: 'string', description: '消息 ID' },
192
- reaction: { type: 'string', description: '反应表情(如 👍、❤️、🔥)' },
193
- },
194
- required: ['endpoint_id', 'chat_id', 'message_id', 'reaction'],
195
- },
196
- platforms: ['telegram'],
197
- tags: ['telegram'],
198
- execute: async (args) => {
199
- const endpoint = telegram.endpoints.get(args.endpoint_id);
200
- if (!endpoint)
201
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
202
- const success = await endpoint.setMessageReaction(Number(args.chat_id), Number(args.message_id), args.reaction);
203
- return { success, message: success ? `已添加反应 ${args.reaction}` : '操作失败' };
204
- },
205
- }, plugin.name));
206
- disposers.push(toolService.addTool({
207
- name: 'telegram_send_sticker',
208
- description: '发送 Telegram 贴纸',
209
- parameters: {
210
- type: 'object',
211
- properties: {
212
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
213
- chat_id: { type: 'string', description: '聊天 ID' },
214
- sticker: { type: 'string', description: '贴纸 file_id 或 URL' },
215
- },
216
- required: ['endpoint_id', 'chat_id', 'sticker'],
217
- },
218
- platforms: ['telegram'],
219
- tags: ['telegram'],
220
- execute: async (args) => {
221
- const endpoint = telegram.endpoints.get(args.endpoint_id);
222
- if (!endpoint)
223
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
224
- const result = await endpoint.sendStickerMessage(Number(args.chat_id), args.sticker);
225
- return { success: true, message_id: result.message_id, message: '贴纸已发送' };
226
- },
227
- }, plugin.name));
228
- disposers.push(toolService.addTool({
229
- name: 'telegram_set_permissions',
230
- description: '设置 Telegram 群组的默认成员权限',
231
- parameters: {
232
- type: 'object',
233
- properties: {
234
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
235
- chat_id: { type: 'string', description: '聊天 ID' },
236
- can_send_messages: { type: 'boolean', description: '是否可以发消息' },
237
- can_send_photos: { type: 'boolean', description: '是否可以发图片' },
238
- can_send_videos: { type: 'boolean', description: '是否可以发视频' },
239
- can_send_polls: { type: 'boolean', description: '是否可以发投票' },
240
- can_send_other_messages: { type: 'boolean', description: '是否可以发贴纸/GIF等' },
241
- can_add_web_page_previews: { type: 'boolean', description: '是否可以添加网页预览' },
242
- can_change_info: { type: 'boolean', description: '是否可以改群信息' },
243
- can_invite_users: { type: 'boolean', description: '是否可以邀请用户' },
244
- can_pin_messages: { type: 'boolean', description: '是否可以置顶消息' },
245
- },
246
- required: ['endpoint_id', 'chat_id'],
247
- },
248
- platforms: ['telegram'],
249
- tags: ['telegram'],
250
- permissions: [platformPermit('manage_chat')],
251
- execute: async (args) => {
252
- const { endpoint: endpointId, chat_id, ...perms } = args;
253
- const endpoint = telegram.endpoints.get(endpointId);
254
- if (!endpoint)
255
- throw new Error(`Endpoint ${endpointId} 不存在`);
256
- const permissions = {};
257
- for (const [k, v] of Object.entries(perms)) {
258
- if (typeof v === 'boolean')
259
- permissions[k] = v;
260
- }
261
- const success = await endpoint.setChatPermissionsAll(Number(chat_id), permissions);
262
- return { success, message: success ? '群权限已更新' : '操作失败' };
263
- },
264
- }, plugin.name));
265
- disposers.push(toolService.addTool({
266
- name: 'telegram_set_description',
267
- description: '设置 Telegram 群组描述',
268
- parameters: {
269
- type: 'object',
270
- properties: {
271
- endpoint_id: { type: 'string', description: 'Endpoint 名称', contextKey: 'endpointId' },
272
- chat_id: { type: 'string', description: '聊天 ID' },
273
- description: { type: 'string', description: '群描述文字' },
274
- },
275
- required: ['endpoint_id', 'chat_id', 'description'],
276
- },
277
- platforms: ['telegram'],
278
- tags: ['telegram'],
279
- execute: async (args) => {
280
- const endpoint = telegram.endpoints.get(args.endpoint_id);
281
- if (!endpoint)
282
- throw new Error(`Endpoint ${args.endpoint_id} 不存在`);
283
- const success = await endpoint.setChatDescription(Number(args.chat_id), args.description);
284
- return { success, message: success ? '群描述已更新' : '操作失败' };
285
- },
286
- }, plugin.name));
287
- return () => disposers.forEach(d => d());
288
- });
289
- // ── Web 控制台 ─────────────────────────────────────────────────────────
290
- useContext("web", (pageManager) => {
291
- pageManager.addEntry({
292
- id: "telegram",
293
- development: path.resolve(import.meta.dirname, "../client/index.tsx"),
294
- production: path.resolve(import.meta.dirname, "../dist/index.js"),
295
- meta: { name: "Telegram" },
296
- });
297
- });
298
- useContext("router", "telegram", (router, telegram) => {
299
- router.get("/api/telegram/endpoints", async (ctx) => {
300
- try {
301
- const endpoints = Array.from(telegram.endpoints.values());
302
- const result = endpoints.map((endpoint) => {
303
- try {
304
- return {
305
- name: endpoint.$config.name,
306
- connected: endpoint.$connected || false,
307
- mode: endpoint.$config.polling !== false ? "polling" : "webhook",
308
- status: endpoint.$connected ? "online" : "offline",
309
- botInfo: endpoint.botInfo ? { username: endpoint.botInfo.username, firstName: endpoint.botInfo.first_name } : null,
310
- };
311
- }
312
- catch {
313
- return { name: endpoint.$config.name, connected: false, mode: "unknown", status: "error", botInfo: null };
314
- }
315
- });
316
- ctx.body = { success: true, data: result };
317
- }
318
- catch {
319
- ctx.status = 500;
320
- ctx.body = { success: false, error: "获取 Endpoint 数据失败" };
321
- }
322
- });
323
- // Endpoint 连接/断开
324
- router.post("/api/telegram/endpoints/:name/connect", async (ctx) => {
325
- try {
326
- const endpoint = telegram.endpoints.get(ctx.params.name);
327
- if (!endpoint) {
328
- ctx.status = 404;
329
- ctx.body = { success: false, error: "Endpoint 不存在" };
330
- return;
331
- }
332
- if (endpoint.$connected) {
333
- ctx.body = { success: true, message: "已经在线" };
334
- return;
335
- }
336
- await endpoint.$connect();
337
- ctx.body = { success: true, message: "连接成功" };
338
- }
339
- catch (e) {
340
- ctx.status = 500;
341
- ctx.body = { success: false, error: e instanceof Error ? e.message : "连接失败" };
342
- }
343
- });
344
- router.post("/api/telegram/endpoints/:name/disconnect", async (ctx) => {
345
- try {
346
- const endpoint = telegram.endpoints.get(ctx.params.name);
347
- if (!endpoint) {
348
- ctx.status = 404;
349
- ctx.body = { success: false, error: "Endpoint 不存在" };
350
- return;
351
- }
352
- if (!endpoint.$connected) {
353
- ctx.body = { success: true, message: "已经离线" };
354
- return;
355
- }
356
- await endpoint.$disconnect();
357
- ctx.body = { success: true, message: "已断开" };
358
- }
359
- catch (e) {
360
- ctx.status = 500;
361
- ctx.body = { success: false, error: e instanceof Error ? e.message : "断开失败" };
362
- }
363
- });
364
- // 快捷操作:创建邀请链接
365
- router.post("/api/telegram/endpoints/:name/invite", async (ctx) => {
366
- try {
367
- const endpoint = telegram.endpoints.get(ctx.params.name);
368
- if (!endpoint) {
369
- ctx.status = 404;
370
- ctx.body = { success: false, error: "Endpoint 不存在" };
371
- return;
372
- }
373
- if (!endpoint.$connected) {
374
- ctx.status = 400;
375
- ctx.body = { success: false, error: "Endpoint 未连接" };
376
- return;
377
- }
378
- const { chat_id } = ctx.request.body || {};
379
- if (!chat_id) {
380
- ctx.status = 400;
381
- ctx.body = { success: false, error: "缺少 chat_id" };
382
- return;
383
- }
384
- const link = await endpoint.createInviteLink(Number(chat_id));
385
- ctx.body = { success: true, data: { invite_link: link } };
386
- }
387
- catch (e) {
388
- ctx.status = 500;
389
- ctx.body = { success: false, error: e instanceof Error ? e.message : "创建邀请链接失败" };
390
- }
391
- });
392
- // 快捷操作:发起投票
393
- router.post("/api/telegram/endpoints/:name/poll", async (ctx) => {
394
- try {
395
- const endpoint = telegram.endpoints.get(ctx.params.name);
396
- if (!endpoint) {
397
- ctx.status = 404;
398
- ctx.body = { success: false, error: "Endpoint 不存在" };
399
- return;
400
- }
401
- if (!endpoint.$connected) {
402
- ctx.status = 400;
403
- ctx.body = { success: false, error: "Endpoint 未连接" };
404
- return;
405
- }
406
- const { chat_id, question, options, is_anonymous, allows_multiple } = ctx.request.body || {};
407
- if (!chat_id || !question || !options?.length) {
408
- ctx.status = 400;
409
- ctx.body = { success: false, error: "缺少 chat_id, question 或 options" };
410
- return;
411
- }
412
- if (options.length < 2) {
413
- ctx.status = 400;
414
- ctx.body = { success: false, error: "至少需要 2 个选项" };
415
- return;
416
- }
417
- const result = await endpoint.sendPoll(Number(chat_id), question, options, is_anonymous ?? true, allows_multiple ?? false);
418
- ctx.body = { success: true, data: { message_id: result.message_id } };
419
- }
420
- catch (e) {
421
- ctx.status = 500;
422
- ctx.body = { success: false, error: e instanceof Error ? e.message : "发起投票失败" };
423
- }
424
- });
425
- // 快捷操作:获取群管理员
426
- router.get("/api/telegram/endpoints/:name/admins", async (ctx) => {
427
- try {
428
- const endpoint = telegram.endpoints.get(ctx.params.name);
429
- if (!endpoint) {
430
- ctx.status = 404;
431
- ctx.body = { success: false, error: "Endpoint 不存在" };
432
- return;
433
- }
434
- if (!endpoint.$connected) {
435
- ctx.status = 400;
436
- ctx.body = { success: false, error: "Endpoint 未连接" };
437
- return;
438
- }
439
- const chat_id = ctx.query.chat_id;
440
- if (!chat_id) {
441
- ctx.status = 400;
442
- ctx.body = { success: false, error: "缺少 chat_id" };
443
- return;
444
- }
445
- const admins = await endpoint.getChatAdmins(Number(chat_id));
446
- ctx.body = {
447
- success: true,
448
- data: admins.map((a) => ({
449
- user_id: a.user.id,
450
- username: a.user.username,
451
- first_name: a.user.first_name,
452
- status: a.status,
453
- })),
454
- };
455
- }
456
- catch (e) {
457
- ctx.status = 500;
458
- ctx.body = { success: false, error: e instanceof Error ? e.message : "获取管理员失败" };
459
- }
460
- });
461
- });
462
- //# sourceMappingURL=index.js.map
1
+ export { TelegramEndpoint, } from './endpoint.js';
2
+ export { botApiUrl, formatCallbackContent, formatInboundContent, formatOutboundActions, normalizeWebhookPath, resolveChannel, resolveTelegramConfig, senderDisplayName, } from './protocol.js';
3
+ export { getTelegramAgentDeps, registerTelegramAgentEndpoint, setTelegramAgentDeps, } from './telegram-agent-deps.js';
4
+ export { checkTelegramPlatformPermit, normalizeTelegramChatMember, platformPermit, registerTelegramPlatformPermitChecker, telegramGroupPermitResolver, } from './platform-permit.js';
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Telegram platform permit — ChatMember 状态 + 细粒度权限
3
3
  */
4
- import type { Message } from 'zhin.js';
4
+ import { type Message } from '@zhin.js/core';
5
5
  export declare function platformPermit(perm: string): string;
6
6
  export declare function telegramGroupPermitResolver(logicalPerm: string): string;
7
7
  export declare function normalizeTelegramChatMember(member: {
@@ -16,4 +16,3 @@ export declare function normalizeTelegramChatMember(member: {
16
16
  };
17
17
  export declare function checkTelegramPlatformPermit(perm: string, message: Message<any>): boolean;
18
18
  export declare function registerTelegramPlatformPermitChecker(): () => void;
19
- //# sourceMappingURL=platform-permit.d.ts.map
@@ -1,4 +1,7 @@
1
- import { registerPlatformPermitChecker } from 'zhin.js';
1
+ /**
2
+ * Telegram platform permit — ChatMember 状态 + 细粒度权限
3
+ */
4
+ import { registerPlatformPermitChecker } from '@zhin.js/core';
2
5
  const ADAPTER = 'telegram';
3
6
  export function platformPermit(perm) {
4
7
  return `platform(${ADAPTER},${perm})`;
@@ -56,4 +59,3 @@ export function checkTelegramPlatformPermit(perm, message) {
56
59
  export function registerTelegramPlatformPermitChecker() {
57
60
  return registerPlatformPermitChecker(ADAPTER, checkTelegramPlatformPermit);
58
61
  }
59
- //# sourceMappingURL=platform-permit.js.map
@@ -0,0 +1,9 @@
1
+ import type { TelegramUpdate } from './protocol.js';
2
+ export interface TelegramPollingHost {
3
+ readonly allowedUpdates: readonly string[];
4
+ callApi<T>(method: string, params?: Record<string, unknown>, signal?: AbortSignal): Promise<T>;
5
+ getUpdateOffset(): number;
6
+ setUpdateOffset(offset: number): void;
7
+ handleUpdate(update: TelegramUpdate): void;
8
+ }
9
+ export declare function runTelegramPollLoop(host: TelegramPollingHost, abortSignal: AbortSignal): Promise<void>;
package/lib/polling.js ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Telegram long-polling loop for getUpdates.
3
+ */
4
+ import { formatCompact, getLogger } from '@zhin.js/logger';
5
+ const logger = getLogger('telegram');
6
+ const RETRY_DELAY_MS = 2_000;
7
+ const BACKOFF_DELAY_MS = 10_000;
8
+ const MAX_CONSECUTIVE_FAILURES = 5;
9
+ const DEFAULT_POLL_TIMEOUT_SEC = 30;
10
+ export async function runTelegramPollLoop(host, abortSignal) {
11
+ let consecutiveFailures = 0;
12
+ while (!abortSignal.aborted) {
13
+ try {
14
+ const updates = await host.callApi('getUpdates', {
15
+ offset: host.getUpdateOffset() || undefined,
16
+ timeout: DEFAULT_POLL_TIMEOUT_SEC,
17
+ allowed_updates: host.allowedUpdates,
18
+ }, abortSignal);
19
+ consecutiveFailures = 0;
20
+ for (const update of updates) {
21
+ host.setUpdateOffset(update.update_id + 1);
22
+ host.handleUpdate(update);
23
+ }
24
+ }
25
+ catch (err) {
26
+ if (abortSignal.aborted)
27
+ return;
28
+ consecutiveFailures += 1;
29
+ logger.error(formatCompact({
30
+ op: 'poll',
31
+ ok: false,
32
+ error: err instanceof Error ? err.message : String(err),
33
+ }));
34
+ await sleep(consecutiveFailures >= MAX_CONSECUTIVE_FAILURES ? BACKOFF_DELAY_MS : RETRY_DELAY_MS, abortSignal);
35
+ if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES)
36
+ consecutiveFailures = 0;
37
+ }
38
+ }
39
+ }
40
+ function sleep(ms, signal) {
41
+ return new Promise((resolve) => {
42
+ if (signal?.aborted) {
43
+ resolve();
44
+ return;
45
+ }
46
+ const timer = setTimeout(resolve, ms);
47
+ signal?.addEventListener('abort', () => {
48
+ clearTimeout(timer);
49
+ resolve();
50
+ }, { once: true });
51
+ });
52
+ }