@zhin.js/adapter-telegram 3.0.0 → 3.0.1
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/CHANGELOG.md +14 -0
- package/README.md +9 -9
- package/client/Dashboard.tsx +32 -32
- package/dist/index.js +1 -1
- package/lib/adapter.d.ts +11 -10
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +39 -38
- package/lib/adapter.js.map +1 -1
- package/lib/{bot.d.ts → endpoint.d.ts} +9 -7
- package/lib/endpoint.d.ts.map +1 -0
- package/lib/{bot.js → endpoint.js} +74 -47
- package/lib/endpoint.js.map +1 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +121 -114
- package/lib/index.js.map +1 -1
- package/lib/platform-permit.d.ts +19 -0
- package/lib/platform-permit.d.ts.map +1 -0
- package/lib/platform-permit.js +59 -0
- package/lib/platform-permit.js.map +1 -0
- package/lib/types.d.ts +3 -3
- package/lib/types.d.ts.map +1 -1
- package/package.json +13 -10
- package/skills/telegram/PERMITS.md +24 -0
- package/src/adapter.ts +31 -29
- package/src/{bot.ts → endpoint.ts} +85 -49
- package/src/index.ts +112 -100
- package/src/platform-permit.ts +73 -0
- package/src/types.ts +3 -3
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js.map +0 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { registerPlatformPermitChecker } from 'zhin.js';
|
|
2
|
+
const ADAPTER = 'telegram';
|
|
3
|
+
export function platformPermit(perm) {
|
|
4
|
+
return `platform(${ADAPTER},${perm})`;
|
|
5
|
+
}
|
|
6
|
+
const FACTORY_PERM_MAP = {
|
|
7
|
+
group_admin: 'chat_administrator',
|
|
8
|
+
group_owner: 'chat_creator',
|
|
9
|
+
};
|
|
10
|
+
export function telegramGroupPermitResolver(logicalPerm) {
|
|
11
|
+
return platformPermit(FACTORY_PERM_MAP[logicalPerm] ?? logicalPerm);
|
|
12
|
+
}
|
|
13
|
+
export function normalizeTelegramChatMember(member) {
|
|
14
|
+
const permissions = [];
|
|
15
|
+
const status = member.status;
|
|
16
|
+
if (status === 'creator') {
|
|
17
|
+
permissions.push('chat_creator', 'chat_administrator', 'restrict_members', 'pin_messages');
|
|
18
|
+
return { role: 'creator', permissions };
|
|
19
|
+
}
|
|
20
|
+
if (status === 'administrator') {
|
|
21
|
+
permissions.push('chat_administrator');
|
|
22
|
+
if (member.can_restrict_members)
|
|
23
|
+
permissions.push('restrict_members');
|
|
24
|
+
if (member.can_pin_messages)
|
|
25
|
+
permissions.push('pin_messages');
|
|
26
|
+
if (member.can_delete_messages)
|
|
27
|
+
permissions.push('delete_messages');
|
|
28
|
+
if (member.can_manage_chat)
|
|
29
|
+
permissions.push('manage_chat');
|
|
30
|
+
return { role: 'administrator', permissions };
|
|
31
|
+
}
|
|
32
|
+
return { role: 'member', permissions };
|
|
33
|
+
}
|
|
34
|
+
function senderPermits(message) {
|
|
35
|
+
const sender = message.$sender;
|
|
36
|
+
return { role: sender.role, permissions: sender.permissions ?? [] };
|
|
37
|
+
}
|
|
38
|
+
export function checkTelegramPlatformPermit(perm, message) {
|
|
39
|
+
const { role, permissions } = senderPermits(message);
|
|
40
|
+
const has = (t) => permissions.includes(t);
|
|
41
|
+
switch (perm) {
|
|
42
|
+
case 'chat_creator':
|
|
43
|
+
return role === 'creator' || has('chat_creator');
|
|
44
|
+
case 'chat_administrator':
|
|
45
|
+
return role === 'creator' || role === 'administrator' || has('chat_administrator');
|
|
46
|
+
case 'restrict_members':
|
|
47
|
+
return has('restrict_members') || role === 'creator';
|
|
48
|
+
case 'pin_messages':
|
|
49
|
+
return has('pin_messages') || role === 'creator';
|
|
50
|
+
case 'manage_chat':
|
|
51
|
+
return has('manage_chat') || role === 'creator';
|
|
52
|
+
default:
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function registerTelegramPlatformPermitChecker() {
|
|
57
|
+
return registerPlatformPermitChecker(ADAPTER, checkTelegramPlatformPermit);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=platform-permit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-permit.js","sourceRoot":"","sources":["../src/platform-permit.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,6BAA6B,EAAE,MAAM,SAAS,CAAC;AAExD,MAAM,OAAO,GAAG,UAAU,CAAC;AAE3B,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,YAAY,OAAO,IAAI,IAAI,GAAG,CAAC;AACxC,CAAC;AAED,MAAM,gBAAgB,GAA2B;IAC/C,WAAW,EAAE,oBAAoB;IACjC,WAAW,EAAE,cAAc;CAC5B,CAAC;AAEF,MAAM,UAAU,2BAA2B,CAAC,WAAmB;IAC7D,OAAO,cAAc,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,WAAW,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,MAM3C;IACC,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,cAAc,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,cAAc,CAAC,CAAC;QAC3F,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;IAC1C,CAAC;IACD,IAAI,MAAM,KAAK,eAAe,EAAE,CAAC;QAC/B,WAAW,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACvC,IAAI,MAAM,CAAC,oBAAoB;YAAE,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACtE,IAAI,MAAM,CAAC,gBAAgB;YAAE,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC9D,IAAI,MAAM,CAAC,mBAAmB;YAAE,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACpE,IAAI,MAAM,CAAC,eAAe;YAAE,WAAW,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC5D,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,aAAa,CAAC,OAAqB;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,OAAoD,CAAC;IAC5E,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,IAAY,EAAE,OAAqB;IAC7E,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEnD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,cAAc;YACjB,OAAO,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,cAAc,CAAC,CAAC;QACnD,KAAK,oBAAoB;YACvB,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,eAAe,IAAI,GAAG,CAAC,oBAAoB,CAAC,CAAC;QACrF,KAAK,kBAAkB;YACrB,OAAO,GAAG,CAAC,kBAAkB,CAAC,IAAI,IAAI,KAAK,SAAS,CAAC;QACvD,KAAK,cAAc;YACjB,OAAO,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,KAAK,SAAS,CAAC;QACnD,KAAK,aAAa;YAChB,OAAO,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,KAAK,SAAS,CAAC;QAClD;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qCAAqC;IACnD,OAAO,6BAA6B,CAAC,OAAO,EAAE,2BAA2B,CAAC,CAAC;AAC7E,CAAC"}
|
package/lib/types.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface TelegramSenderInfo {
|
|
|
11
11
|
isAdmin?: boolean;
|
|
12
12
|
status?: string;
|
|
13
13
|
}
|
|
14
|
-
export interface
|
|
14
|
+
export interface TelegramEndpointConfig {
|
|
15
15
|
context: "telegram";
|
|
16
16
|
token: string;
|
|
17
17
|
name: string;
|
|
@@ -23,7 +23,7 @@ export interface TelegramBotConfig {
|
|
|
23
23
|
};
|
|
24
24
|
allowedUpdates?: string[];
|
|
25
25
|
}
|
|
26
|
-
export interface
|
|
27
|
-
$config:
|
|
26
|
+
export interface TelegramEndpoint {
|
|
27
|
+
$config: TelegramEndpointConfig;
|
|
28
28
|
}
|
|
29
29
|
//# sourceMappingURL=types.d.ts.map
|
package/lib/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjE,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjE,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,sBAAsB,CAAC;CACjC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/adapter-telegram",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Zhin.js adapter for Telegram",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -35,23 +35,26 @@
|
|
|
35
35
|
"telegraf": "^4.16.3"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@types/node": "^25.9.
|
|
38
|
+
"@types/node": "^25.9.2",
|
|
39
39
|
"@types/react": "^19.2.15",
|
|
40
40
|
"@types/react-dom": "^19.2.3",
|
|
41
41
|
"lucide-react": "^1.17.0",
|
|
42
42
|
"typescript": "^6.0.3",
|
|
43
|
-
"@zhin.js/cli": "1.0.
|
|
44
|
-
"@zhin.js/
|
|
43
|
+
"@zhin.js/cli": "1.0.89",
|
|
44
|
+
"@zhin.js/client": "2.0.3",
|
|
45
45
|
"@zhin.js/contract": "1.0.1",
|
|
46
|
-
"zhin.js": "
|
|
46
|
+
"@zhin.js/host-api": "1.0.1",
|
|
47
|
+
"@zhin.js/logger": "0.1.71",
|
|
48
|
+
"zhin.js": "2.0.1",
|
|
49
|
+
"@zhin.js/host-router": "1.0.1"
|
|
47
50
|
},
|
|
48
51
|
"peerDependencies": {
|
|
49
|
-
"@zhin.js/client": "2.0.
|
|
52
|
+
"@zhin.js/client": "2.0.3",
|
|
53
|
+
"@zhin.js/host-api": "1.0.1",
|
|
50
54
|
"@zhin.js/contract": "1.0.1",
|
|
51
|
-
"@zhin.js/host-
|
|
52
|
-
"@zhin.js/
|
|
53
|
-
"
|
|
54
|
-
"zhin.js": "2.0.0"
|
|
55
|
+
"@zhin.js/host-router": "1.0.1",
|
|
56
|
+
"@zhin.js/logger": "0.1.71",
|
|
57
|
+
"zhin.js": "2.0.1"
|
|
55
58
|
},
|
|
56
59
|
"peerDependenciesMeta": {
|
|
57
60
|
"@zhin.js/client": {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Telegram Platform Permits
|
|
2
|
+
|
|
3
|
+
## 入站字段
|
|
4
|
+
|
|
5
|
+
群/超级群消息经 `getChatMember`(TTL 60s)写入:
|
|
6
|
+
|
|
7
|
+
| 字段 | 取值 |
|
|
8
|
+
|------|------|
|
|
9
|
+
| `$sender.role` | `creator` · `administrator` · `member` |
|
|
10
|
+
| `$sender.permissions` | `chat_creator` · `chat_administrator` · `restrict_members` · `pin_messages` · `manage_chat` · … |
|
|
11
|
+
|
|
12
|
+
## Permit 词汇表
|
|
13
|
+
|
|
14
|
+
| `platform(telegram,…)` | 含义 |
|
|
15
|
+
|------------------------|------|
|
|
16
|
+
| `chat_creator` | 群主 |
|
|
17
|
+
| `chat_administrator` | 管理员 |
|
|
18
|
+
| `restrict_members` | 可禁言成员 |
|
|
19
|
+
| `pin_messages` | 可置顶 |
|
|
20
|
+
| `manage_chat` | 可改群默认权限 |
|
|
21
|
+
|
|
22
|
+
## 工厂映射
|
|
23
|
+
|
|
24
|
+
`group_admin` → `chat_administrator` · `group_owner` → `chat_creator`
|
package/src/adapter.ts
CHANGED
|
@@ -5,54 +5,56 @@ import {
|
|
|
5
5
|
Adapter,
|
|
6
6
|
Plugin,
|
|
7
7
|
} from "zhin.js";
|
|
8
|
-
import {
|
|
9
|
-
import type {
|
|
8
|
+
import { TelegramEndpoint } from "./endpoint.js";
|
|
9
|
+
import type { TelegramEndpointConfig } from "./types.js";
|
|
10
|
+
|
|
11
|
+
export class TelegramAdapter extends Adapter<TelegramEndpoint> {
|
|
12
|
+
static override readonly capabilities = ['inbound', 'outbound'] as const;
|
|
10
13
|
|
|
11
|
-
export class TelegramAdapter extends Adapter<TelegramBot> {
|
|
12
14
|
constructor(plugin: Plugin) {
|
|
13
15
|
super(plugin, "telegram", []);
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
return new
|
|
18
|
+
createEndpoint(config: TelegramEndpointConfig): TelegramEndpoint {
|
|
19
|
+
return new TelegramEndpoint(this, config);
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
// ── IGroupManagement 标准群管方法 ──────────────────────────────────
|
|
21
23
|
|
|
22
|
-
async kickMember(
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
25
|
-
return
|
|
24
|
+
async kickMember(endpointId: string, sceneId: string, userId: string) {
|
|
25
|
+
const endpoint = this.endpoints.get(endpointId);
|
|
26
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
|
|
27
|
+
return endpoint.kickMember(Number(sceneId), Number(userId));
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
async unbanMember(
|
|
29
|
-
const
|
|
30
|
-
if (!
|
|
31
|
-
return
|
|
30
|
+
async unbanMember(endpointId: string, sceneId: string, userId: string) {
|
|
31
|
+
const endpoint = this.endpoints.get(endpointId);
|
|
32
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
|
|
33
|
+
return endpoint.unbanMember(Number(sceneId), Number(userId));
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
async muteMember(
|
|
35
|
-
const
|
|
36
|
-
if (!
|
|
37
|
-
return
|
|
36
|
+
async muteMember(endpointId: string, sceneId: string, userId: string, duration = 600) {
|
|
37
|
+
const endpoint = this.endpoints.get(endpointId);
|
|
38
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
|
|
39
|
+
return endpoint.muteMember(Number(sceneId), Number(userId), duration);
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
async setAdmin(
|
|
41
|
-
const
|
|
42
|
-
if (!
|
|
43
|
-
return
|
|
42
|
+
async setAdmin(endpointId: string, sceneId: string, userId: string, enable = true) {
|
|
43
|
+
const endpoint = this.endpoints.get(endpointId);
|
|
44
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
|
|
45
|
+
return endpoint.setAdmin(Number(sceneId), Number(userId), enable);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
async setGroupName(
|
|
47
|
-
const
|
|
48
|
-
if (!
|
|
49
|
-
return
|
|
48
|
+
async setGroupName(endpointId: string, sceneId: string, name: string) {
|
|
49
|
+
const endpoint = this.endpoints.get(endpointId);
|
|
50
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
|
|
51
|
+
return endpoint.setChatTitle(Number(sceneId), name);
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
async getGroupInfo(
|
|
53
|
-
const
|
|
54
|
-
if (!
|
|
55
|
-
return
|
|
54
|
+
async getGroupInfo(endpointId: string, sceneId: string) {
|
|
55
|
+
const endpoint = this.endpoints.get(endpointId);
|
|
56
|
+
if (!endpoint) throw new Error(`Endpoint ${endpointId} 不存在`);
|
|
57
|
+
return endpoint.getChatInfo(Number(sceneId));
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
// ── 生命周期 ───────────────────────────────────────────────────────
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Telegram
|
|
2
|
+
* Telegram Endpoint 实现
|
|
3
3
|
*/
|
|
4
4
|
import { Telegraf, type Context as TelegrafContext } from "telegraf";
|
|
5
5
|
import type { Message as TelegramMessage, Update, MessageEntity, ChatMember } from "telegraf/types";
|
|
6
6
|
import {
|
|
7
|
-
|
|
7
|
+
Endpoint,
|
|
8
8
|
Message,
|
|
9
9
|
SendOptions,
|
|
10
10
|
SendContent,
|
|
@@ -12,10 +12,11 @@ import {
|
|
|
12
12
|
segment,
|
|
13
13
|
type QuotedMessagePayload,
|
|
14
14
|
} from "zhin.js";
|
|
15
|
-
import type {
|
|
15
|
+
import type { TelegramEndpointConfig, TelegramSenderInfo } from "./types.js";
|
|
16
16
|
import type { TelegramAdapter } from "./adapter.js";
|
|
17
|
+
import { normalizeTelegramChatMember } from "./platform-permit.js";
|
|
17
18
|
|
|
18
|
-
export class
|
|
19
|
+
export class TelegramEndpoint extends Telegraf implements Endpoint<TelegramEndpointConfig, TelegramMessage> {
|
|
19
20
|
$connected: boolean = false;
|
|
20
21
|
/** message_id -> chat_id,用于在仅有 message_id 的场景执行 reaction 操作 */
|
|
21
22
|
private readonly messageChatMap = new Map<string, string>();
|
|
@@ -30,7 +31,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
30
31
|
return this.$config.name;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
constructor(public adapter: TelegramAdapter, public $config:
|
|
34
|
+
constructor(public adapter: TelegramAdapter, public $config: TelegramEndpointConfig) {
|
|
34
35
|
super($config.token);
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -77,7 +78,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
77
78
|
this.$connected = true;
|
|
78
79
|
const me = await this.telegram.getMe();
|
|
79
80
|
this.pluginLogger.info(
|
|
80
|
-
`Telegram
|
|
81
|
+
`Telegram endpoint ${this.$config.name} connected successfully as @${me.username}`
|
|
81
82
|
);
|
|
82
83
|
} catch (error) {
|
|
83
84
|
this.pluginLogger.error("Failed to connect Telegram bot:", error);
|
|
@@ -91,17 +92,52 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
91
92
|
(this as unknown as import('node:events').EventEmitter).removeAllListeners();
|
|
92
93
|
await this.stop();
|
|
93
94
|
this.$connected = false;
|
|
94
|
-
this.pluginLogger.info(`Telegram
|
|
95
|
+
this.pluginLogger.info(`Telegram endpoint ${this.$config.name} disconnected`);
|
|
95
96
|
} catch (error) {
|
|
96
97
|
this.pluginLogger.error("Error disconnecting Telegram bot:", error);
|
|
97
98
|
throw error;
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
private chatMemberCache = new Map<string, { at: number; role?: string; permissions: string[] }>();
|
|
103
|
+
|
|
104
|
+
private async enrichGroupSender(
|
|
105
|
+
message: Message<TelegramMessage>,
|
|
106
|
+
msg: TelegramMessage,
|
|
107
|
+
): Promise<void> {
|
|
108
|
+
if (message.$channel.type !== "group" || !msg.from?.id) return;
|
|
109
|
+
const chatId = Number(msg.chat.id);
|
|
110
|
+
const userId = msg.from.id;
|
|
111
|
+
const key = `${chatId}:${userId}`;
|
|
112
|
+
const now = Date.now();
|
|
113
|
+
const cached = this.chatMemberCache.get(key);
|
|
114
|
+
if (cached && now - cached.at < 60_000) {
|
|
115
|
+
message.$sender.role = cached.role;
|
|
116
|
+
message.$sender.permissions = cached.permissions;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const member = await this.getChatMember(chatId, userId);
|
|
121
|
+
const normalized = normalizeTelegramChatMember(member as {
|
|
122
|
+
status?: string;
|
|
123
|
+
can_restrict_members?: boolean;
|
|
124
|
+
can_pin_messages?: boolean;
|
|
125
|
+
can_delete_messages?: boolean;
|
|
126
|
+
can_manage_chat?: boolean;
|
|
127
|
+
});
|
|
128
|
+
this.chatMemberCache.set(key, { at: now, ...normalized });
|
|
129
|
+
message.$sender.role = normalized.role;
|
|
130
|
+
message.$sender.permissions = normalized.permissions;
|
|
131
|
+
} catch {
|
|
132
|
+
// 保守拒绝:无角色快照
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
101
136
|
private async handleTelegramMessage(ctx: TelegrafContext): Promise<void> {
|
|
102
137
|
if (!ctx.message) return;
|
|
103
138
|
|
|
104
139
|
const message = this.$formatMessage(ctx.message as TelegramMessage);
|
|
140
|
+
await this.enrichGroupSender(message, ctx.message as TelegramMessage);
|
|
105
141
|
this.adapter.emit("message.receive", message);
|
|
106
142
|
this.pluginLogger.debug(
|
|
107
143
|
`${this.$config.name} recv ${message.$channel.type}(${message.$channel.id}): ${segment.raw(message.$content)}`
|
|
@@ -121,7 +157,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
121
157
|
const result = Message.from(msg, {
|
|
122
158
|
$id: msg.message_id.toString(),
|
|
123
159
|
$adapter: "telegram",
|
|
124
|
-
$
|
|
160
|
+
$endpoint: this.$config.name,
|
|
125
161
|
$sender: {
|
|
126
162
|
id: msg.from?.id.toString() || "",
|
|
127
163
|
name: msg.from?.username || msg.from?.first_name || "Unknown",
|
|
@@ -155,7 +191,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
155
191
|
|
|
156
192
|
return await this.adapter.sendMessage({
|
|
157
193
|
context: "telegram",
|
|
158
|
-
|
|
194
|
+
endpoint: this.$config.name,
|
|
159
195
|
id: channelId,
|
|
160
196
|
type: channelType,
|
|
161
197
|
content: content,
|
|
@@ -207,7 +243,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
207
243
|
const result = Message.from(query, {
|
|
208
244
|
$id: query.id,
|
|
209
245
|
$adapter: "telegram",
|
|
210
|
-
$
|
|
246
|
+
$endpoint: this.$config.name,
|
|
211
247
|
$sender: {
|
|
212
248
|
id: query.from.id.toString(),
|
|
213
249
|
name: query.from.username || query.from.first_name,
|
|
@@ -648,15 +684,15 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
648
684
|
}
|
|
649
685
|
|
|
650
686
|
// If neither media nor text was sent, this is an error
|
|
651
|
-
throw new Error("
|
|
687
|
+
throw new Error("TelegramEndpoint.$sendMessage: No media or text content to send.");
|
|
652
688
|
}
|
|
653
689
|
|
|
654
690
|
async $recallMessage(id: string): Promise<void> {
|
|
655
691
|
// Telegram requires both chat_id and message_id to delete a message
|
|
656
|
-
// The
|
|
692
|
+
// The Endpoint interface only provides message_id, making recall impossible
|
|
657
693
|
// Users should use message.$recall() instead, which has the full context
|
|
658
694
|
throw new Error(
|
|
659
|
-
"
|
|
695
|
+
"TelegramEndpoint.$recallMessage: Message recall not supported without chat_id. " +
|
|
660
696
|
"Use message.$recall() method instead, which contains the required context."
|
|
661
697
|
);
|
|
662
698
|
}
|
|
@@ -683,7 +719,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
683
719
|
async $addReaction(messageId: string, emoji: string): Promise<string | null> {
|
|
684
720
|
const ref = this.resolveTelegramMessageRef(messageId);
|
|
685
721
|
if (!ref) {
|
|
686
|
-
this.pluginLogger.warn(`Telegram
|
|
722
|
+
this.pluginLogger.warn(`Telegram Endpoint ${this.$id} 无法根据 message_id=${messageId} 定位 chat_id,跳过 addReaction`);
|
|
687
723
|
return null;
|
|
688
724
|
}
|
|
689
725
|
|
|
@@ -691,7 +727,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
691
727
|
await this.setMessageReaction(ref.chatId, ref.msgId, emoji);
|
|
692
728
|
return emoji;
|
|
693
729
|
} catch (error) {
|
|
694
|
-
this.pluginLogger.error(`Telegram
|
|
730
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 添加 reaction 失败:`, error);
|
|
695
731
|
return null;
|
|
696
732
|
}
|
|
697
733
|
}
|
|
@@ -699,7 +735,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
699
735
|
async $removeReaction(messageId: string, _reactionId: string): Promise<void> {
|
|
700
736
|
const ref = this.resolveTelegramMessageRef(messageId);
|
|
701
737
|
if (!ref) {
|
|
702
|
-
this.pluginLogger.warn(`Telegram
|
|
738
|
+
this.pluginLogger.warn(`Telegram Endpoint ${this.$id} 无法根据 message_id=${messageId} 定位 chat_id,跳过 removeReaction`);
|
|
703
739
|
return;
|
|
704
740
|
}
|
|
705
741
|
|
|
@@ -710,7 +746,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
710
746
|
reaction: [],
|
|
711
747
|
});
|
|
712
748
|
} catch (error) {
|
|
713
|
-
this.pluginLogger.error(`Telegram
|
|
749
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 移除 reaction 失败:`, error);
|
|
714
750
|
}
|
|
715
751
|
}
|
|
716
752
|
// ==================== 群组管理 API ====================
|
|
@@ -724,10 +760,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
724
760
|
async kickMember(chatId: number, userId: number, untilDate?: number): Promise<boolean> {
|
|
725
761
|
try {
|
|
726
762
|
await this.telegram.banChatMember(chatId, userId, untilDate);
|
|
727
|
-
this.pluginLogger.info(`Telegram
|
|
763
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 踢出用户 ${userId} 从聊天 ${chatId}`);
|
|
728
764
|
return true;
|
|
729
765
|
} catch (error) {
|
|
730
|
-
this.pluginLogger.error(`Telegram
|
|
766
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 踢出用户失败:`, error);
|
|
731
767
|
throw error;
|
|
732
768
|
}
|
|
733
769
|
}
|
|
@@ -740,10 +776,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
740
776
|
async unbanMember(chatId: number, userId: number): Promise<boolean> {
|
|
741
777
|
try {
|
|
742
778
|
await this.telegram.unbanChatMember(chatId, userId, { only_if_banned: true });
|
|
743
|
-
this.pluginLogger.info(`Telegram
|
|
779
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 解除用户 ${userId} 的封禁(聊天 ${chatId})`);
|
|
744
780
|
return true;
|
|
745
781
|
} catch (error) {
|
|
746
|
-
this.pluginLogger.error(`Telegram
|
|
782
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 解除封禁失败:`, error);
|
|
747
783
|
throw error;
|
|
748
784
|
}
|
|
749
785
|
}
|
|
@@ -770,10 +806,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
770
806
|
permissions,
|
|
771
807
|
until_date: untilDate,
|
|
772
808
|
});
|
|
773
|
-
this.pluginLogger.info(`Telegram
|
|
809
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 限制用户 ${userId} 权限(聊天 ${chatId})`);
|
|
774
810
|
return true;
|
|
775
811
|
} catch (error) {
|
|
776
|
-
this.pluginLogger.error(`Telegram
|
|
812
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 限制权限失败:`, error);
|
|
777
813
|
throw error;
|
|
778
814
|
}
|
|
779
815
|
}
|
|
@@ -802,7 +838,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
802
838
|
can_add_web_page_previews: true,
|
|
803
839
|
},
|
|
804
840
|
});
|
|
805
|
-
this.pluginLogger.info(`Telegram
|
|
841
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 解除用户 ${userId} 禁言(聊天 ${chatId})`);
|
|
806
842
|
} else {
|
|
807
843
|
const untilDate = Math.floor(Date.now() / 1000) + duration;
|
|
808
844
|
await this.telegram.restrictChatMember(chatId, userId, {
|
|
@@ -820,11 +856,11 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
820
856
|
},
|
|
821
857
|
until_date: untilDate,
|
|
822
858
|
});
|
|
823
|
-
this.pluginLogger.info(`Telegram
|
|
859
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 禁言用户 ${userId} ${duration}秒(聊天 ${chatId})`);
|
|
824
860
|
}
|
|
825
861
|
return true;
|
|
826
862
|
} catch (error) {
|
|
827
|
-
this.pluginLogger.error(`Telegram
|
|
863
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 禁言操作失败:`, error);
|
|
828
864
|
throw error;
|
|
829
865
|
}
|
|
830
866
|
}
|
|
@@ -860,10 +896,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
860
896
|
can_pin_messages: false,
|
|
861
897
|
});
|
|
862
898
|
}
|
|
863
|
-
this.pluginLogger.info(`Telegram
|
|
899
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} ${promote ? '提升' : '降级'}用户 ${userId} 为管理员(聊天 ${chatId})`);
|
|
864
900
|
return true;
|
|
865
901
|
} catch (error) {
|
|
866
|
-
this.pluginLogger.error(`Telegram
|
|
902
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置管理员失败:`, error);
|
|
867
903
|
throw error;
|
|
868
904
|
}
|
|
869
905
|
}
|
|
@@ -876,10 +912,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
876
912
|
async setChatTitle(chatId: number, title: string): Promise<boolean> {
|
|
877
913
|
try {
|
|
878
914
|
await this.telegram.setChatTitle(chatId, title);
|
|
879
|
-
this.pluginLogger.info(`Telegram
|
|
915
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 设置聊天 ${chatId} 标题为 "${title}"`);
|
|
880
916
|
return true;
|
|
881
917
|
} catch (error) {
|
|
882
|
-
this.pluginLogger.error(`Telegram
|
|
918
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置标题失败:`, error);
|
|
883
919
|
throw error;
|
|
884
920
|
}
|
|
885
921
|
}
|
|
@@ -892,10 +928,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
892
928
|
async setChatDescription(chatId: number, description: string): Promise<boolean> {
|
|
893
929
|
try {
|
|
894
930
|
await this.telegram.setChatDescription(chatId, description);
|
|
895
|
-
this.pluginLogger.info(`Telegram
|
|
931
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 设置聊天 ${chatId} 描述`);
|
|
896
932
|
return true;
|
|
897
933
|
} catch (error) {
|
|
898
|
-
this.pluginLogger.error(`Telegram
|
|
934
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置描述失败:`, error);
|
|
899
935
|
throw error;
|
|
900
936
|
}
|
|
901
937
|
}
|
|
@@ -908,10 +944,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
908
944
|
async pinMessage(chatId: number, messageId: number): Promise<boolean> {
|
|
909
945
|
try {
|
|
910
946
|
await this.telegram.pinChatMessage(chatId, messageId);
|
|
911
|
-
this.pluginLogger.info(`Telegram
|
|
947
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 置顶消息 ${messageId}(聊天 ${chatId})`);
|
|
912
948
|
return true;
|
|
913
949
|
} catch (error) {
|
|
914
|
-
this.pluginLogger.error(`Telegram
|
|
950
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 置顶消息失败:`, error);
|
|
915
951
|
throw error;
|
|
916
952
|
}
|
|
917
953
|
}
|
|
@@ -928,10 +964,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
928
964
|
} else {
|
|
929
965
|
await this.telegram.unpinAllChatMessages(chatId);
|
|
930
966
|
}
|
|
931
|
-
this.pluginLogger.info(`Telegram
|
|
967
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 取消置顶消息(聊天 ${chatId})`);
|
|
932
968
|
return true;
|
|
933
969
|
} catch (error) {
|
|
934
|
-
this.pluginLogger.error(`Telegram
|
|
970
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 取消置顶失败:`, error);
|
|
935
971
|
throw error;
|
|
936
972
|
}
|
|
937
973
|
}
|
|
@@ -944,7 +980,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
944
980
|
try {
|
|
945
981
|
return await this.telegram.getChat(chatId);
|
|
946
982
|
} catch (error) {
|
|
947
|
-
this.pluginLogger.error(`Telegram
|
|
983
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 获取聊天信息失败:`, error);
|
|
948
984
|
throw error;
|
|
949
985
|
}
|
|
950
986
|
}
|
|
@@ -958,7 +994,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
958
994
|
try {
|
|
959
995
|
return await this.telegram.getChatMember(chatId, userId);
|
|
960
996
|
} catch (error) {
|
|
961
|
-
this.pluginLogger.error(`Telegram
|
|
997
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 获取成员信息失败:`, error);
|
|
962
998
|
throw error;
|
|
963
999
|
}
|
|
964
1000
|
}
|
|
@@ -971,7 +1007,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
971
1007
|
try {
|
|
972
1008
|
return await this.telegram.getChatAdministrators(chatId);
|
|
973
1009
|
} catch (error) {
|
|
974
|
-
this.pluginLogger.error(`Telegram
|
|
1010
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 获取管理员列表失败:`, error);
|
|
975
1011
|
throw error;
|
|
976
1012
|
}
|
|
977
1013
|
}
|
|
@@ -984,7 +1020,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
984
1020
|
try {
|
|
985
1021
|
return await this.telegram.getChatMembersCount(chatId);
|
|
986
1022
|
} catch (error) {
|
|
987
|
-
this.pluginLogger.error(`Telegram
|
|
1023
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 获取成员数量失败:`, error);
|
|
988
1024
|
throw error;
|
|
989
1025
|
}
|
|
990
1026
|
}
|
|
@@ -996,10 +1032,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
996
1032
|
async createInviteLink(chatId: number): Promise<string> {
|
|
997
1033
|
try {
|
|
998
1034
|
const link = await this.telegram.createChatInviteLink(chatId, {});
|
|
999
|
-
this.pluginLogger.info(`Telegram
|
|
1035
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 创建邀请链接(聊天 ${chatId})`);
|
|
1000
1036
|
return link.invite_link;
|
|
1001
1037
|
} catch (error) {
|
|
1002
|
-
this.pluginLogger.error(`Telegram
|
|
1038
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 创建邀请链接失败:`, error);
|
|
1003
1039
|
throw error;
|
|
1004
1040
|
}
|
|
1005
1041
|
}
|
|
@@ -1010,10 +1046,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
1010
1046
|
is_anonymous: isAnonymous,
|
|
1011
1047
|
allows_multiple_answers: allowsMultipleAnswers,
|
|
1012
1048
|
} as any);
|
|
1013
|
-
this.pluginLogger.info(`Telegram
|
|
1049
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 发送投票到 ${chatId}`);
|
|
1014
1050
|
return result;
|
|
1015
1051
|
} catch (error) {
|
|
1016
|
-
this.pluginLogger.error(`Telegram
|
|
1052
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 发送投票失败:`, error);
|
|
1017
1053
|
throw error;
|
|
1018
1054
|
}
|
|
1019
1055
|
}
|
|
@@ -1027,7 +1063,7 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
1027
1063
|
});
|
|
1028
1064
|
return true;
|
|
1029
1065
|
} catch (error) {
|
|
1030
|
-
this.pluginLogger.error(`Telegram
|
|
1066
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置反应失败:`, error);
|
|
1031
1067
|
throw error;
|
|
1032
1068
|
}
|
|
1033
1069
|
}
|
|
@@ -1035,10 +1071,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
1035
1071
|
async sendStickerMessage(chatId: number, sticker: string): Promise<TelegramMessage> {
|
|
1036
1072
|
try {
|
|
1037
1073
|
const result = await this.telegram.sendSticker(chatId, sticker);
|
|
1038
|
-
this.pluginLogger.info(`Telegram
|
|
1074
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 发送贴纸到 ${chatId}`);
|
|
1039
1075
|
return result;
|
|
1040
1076
|
} catch (error) {
|
|
1041
|
-
this.pluginLogger.error(`Telegram
|
|
1077
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 发送贴纸失败:`, error);
|
|
1042
1078
|
throw error;
|
|
1043
1079
|
}
|
|
1044
1080
|
}
|
|
@@ -1061,10 +1097,10 @@ export class TelegramBot extends Telegraf implements Bot<TelegramBotConfig, Tele
|
|
|
1061
1097
|
}): Promise<boolean> {
|
|
1062
1098
|
try {
|
|
1063
1099
|
await this.telegram.setChatPermissions(chatId, permissions);
|
|
1064
|
-
this.pluginLogger.info(`Telegram
|
|
1100
|
+
this.pluginLogger.info(`Telegram Endpoint ${this.$id} 设置聊天 ${chatId} 权限`);
|
|
1065
1101
|
return true;
|
|
1066
1102
|
} catch (error) {
|
|
1067
|
-
this.pluginLogger.error(`Telegram
|
|
1103
|
+
this.pluginLogger.error(`Telegram Endpoint ${this.$id} 设置聊天权限失败:`, error);
|
|
1068
1104
|
throw error;
|
|
1069
1105
|
}
|
|
1070
1106
|
}
|