@zhin.js/adapter-telegram 1.0.68 → 1.1.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/CHANGELOG.md +825 -16
- package/README.md +106 -77
- package/adapters/telegram.js +34 -0
- package/adapters/telegram.ts +39 -0
- package/agent/PERMITS.md +24 -0
- package/agent/tools/create_invite.ts +18 -0
- package/agent/tools/list_admins.ts +24 -0
- package/agent/tools/member_count.ts +16 -0
- package/agent/tools/pin_message.ts +19 -0
- package/agent/tools/react.ts +18 -0
- package/agent/tools/send_poll.ts +32 -0
- package/agent/tools/send_sticker.ts +17 -0
- package/agent/tools/set_description.ts +17 -0
- package/agent/tools/set_permissions.ts +31 -0
- package/agent/tools/unpin_message.ts +19 -0
- package/commands/endpoint/add/[id].js +3 -0
- package/commands/endpoint/add/[id].ts +3 -0
- package/commands/endpoint/list.js +3 -0
- package/commands/endpoint/list.ts +3 -0
- package/commands/endpoint/remove/[id].js +3 -0
- package/commands/endpoint/remove/[id].ts +3 -0
- package/lib/client.d.ts +12 -0
- package/lib/client.js +2 -0
- package/lib/endpoint.d.ts +112 -0
- package/lib/endpoint.js +535 -0
- package/lib/index.d.ts +4 -18
- package/lib/index.js +4 -455
- package/lib/markdown-to-html.d.ts +9 -0
- package/lib/markdown-to-html.js +75 -0
- package/lib/platform-permit.d.ts +17 -0
- package/lib/platform-permit.js +51 -0
- package/lib/polling.d.ts +9 -0
- package/lib/polling.js +57 -0
- package/lib/protocol.d.ts +299 -0
- package/lib/protocol.js +474 -0
- package/lib/telegram-endpoint-commands.d.ts +1 -0
- package/lib/telegram-endpoint-commands.js +16 -0
- package/lib/telegram-runtime-state.d.ts +1 -0
- package/lib/telegram-runtime-state.js +6 -0
- package/lib/webhook.d.ts +12 -0
- package/lib/webhook.js +55 -0
- package/package.json +59 -28
- package/plugin.js +19 -0
- package/schema.json +110 -0
- package/src/client.ts +16 -0
- package/src/endpoint.ts +679 -0
- package/src/index.ts +39 -426
- package/src/markdown-to-html.ts +86 -0
- package/src/platform-permit.ts +65 -0
- package/src/polling.ts +76 -0
- package/src/protocol.ts +767 -0
- package/src/telegram-endpoint-commands.ts +17 -0
- package/src/telegram-runtime-state.ts +7 -0
- package/src/webhook.ts +75 -0
- package/client/Dashboard.tsx +0 -295
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/client/utils/api.ts +0 -17
- package/dist/index.js +0 -32
- package/lib/adapter.d.ts +0 -18
- package/lib/adapter.d.ts.map +0 -1
- package/lib/adapter.js +0 -55
- package/lib/adapter.js.map +0 -1
- package/lib/bot.d.ts +0 -140
- package/lib/bot.d.ts.map +0 -1
- package/lib/bot.js +0 -866
- package/lib/bot.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/types.d.ts +0 -29
- package/lib/types.d.ts.map +0 -1
- package/lib/types.js +0 -2
- package/lib/types.js.map +0 -1
- package/plugin.yml +0 -3
- package/src/adapter.ts +0 -64
- package/src/bot.ts +0 -983
- package/src/types.ts +0 -32
- /package/{skills/telegram/SKILL.md → agent/skills/telegram.md} +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `telegram.endpoint` 命令族:由 @zhin.js/adapter 的 createEndpointCommands 套件生成。
|
|
3
|
+
* commands/endpoint/ 下的 list / add / remove 直接默认导出这三项。
|
|
4
|
+
*/
|
|
5
|
+
import { createEndpointCommands } from 'zhin.js/adapter';
|
|
6
|
+
import { defineCommand } from 'zhin.js/command';
|
|
7
|
+
import { telegramRuntimeStateToken } from './telegram-runtime-state.js';
|
|
8
|
+
|
|
9
|
+
export const telegramEndpointCommands = createEndpointCommands({
|
|
10
|
+
adapterKey: 'telegram',
|
|
11
|
+
adapterDisplayName: 'Telegram',
|
|
12
|
+
fields: [
|
|
13
|
+
{ key: 'token', required: true, env: true, description: 'Telegram bot token' },
|
|
14
|
+
],
|
|
15
|
+
running: (use) => use(telegramRuntimeStateToken).endpoints.values(),
|
|
16
|
+
describeEntry: (entry) => `token: ${String(entry.token)}`,
|
|
17
|
+
}, defineCommand);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram 插件实例的运行时状态:adapter create() 注册的 endpoint 列表。
|
|
3
|
+
* 由 plugin.ts setup() provide,adapter create 与 `telegram.endpoint` 命令共享(同一 owner generation)。
|
|
4
|
+
*/
|
|
5
|
+
import { defineEndpointRuntimeStateToken } from 'zhin.js/adapter';
|
|
6
|
+
|
|
7
|
+
export const telegramRuntimeStateToken = defineEndpointRuntimeStateToken('telegram');
|
package/src/webhook.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram webhook HTTP: secret token → parse → handle update.
|
|
3
|
+
*/
|
|
4
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
5
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
6
|
+
import type { HttpHost, HttpRouteRegistration } from '@zhin.js/host-http';
|
|
7
|
+
import { getLogger } from '@zhin.js/logger';
|
|
8
|
+
import { readTextBody, type ResolvedTelegramConfig, type TelegramUpdate } from './protocol.js';
|
|
9
|
+
|
|
10
|
+
const logger = getLogger('telegram');
|
|
11
|
+
|
|
12
|
+
/** 等长时才 timingSafeEqual,避免长度差异直接抛异常。 */
|
|
13
|
+
export function safeTokenEqual(a: string, b: string): boolean {
|
|
14
|
+
const bufA = Buffer.from(a, 'utf8');
|
|
15
|
+
const bufB = Buffer.from(b, 'utf8');
|
|
16
|
+
return bufA.length === bufB.length && timingSafeEqual(bufA, bufB);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TelegramWebhookHandler {
|
|
20
|
+
readonly config: ResolvedTelegramConfig;
|
|
21
|
+
readonly isOpen: boolean;
|
|
22
|
+
handleUpdate(update: TelegramUpdate): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function registerTelegramWebhookRoutes(
|
|
26
|
+
http: HttpHost,
|
|
27
|
+
handler: TelegramWebhookHandler,
|
|
28
|
+
): HttpRouteRegistration[] {
|
|
29
|
+
const path = handler.config.webhook!.path;
|
|
30
|
+
return [
|
|
31
|
+
http.route('POST', path, async (request, response) => {
|
|
32
|
+
await handleTelegramWebhookRequest(request, response, handler);
|
|
33
|
+
}, { summary: 'Telegram Bot API webhook', tags: ['telegram'] }),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function handleTelegramWebhookRequest(
|
|
38
|
+
request: IncomingMessage,
|
|
39
|
+
response: ServerResponse,
|
|
40
|
+
handler: TelegramWebhookHandler,
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
try {
|
|
43
|
+
const secret = handler.config.webhook?.secretToken;
|
|
44
|
+
if (secret) {
|
|
45
|
+
const header = request.headers['x-telegram-bot-api-secret-token'];
|
|
46
|
+
const token = Array.isArray(header) ? header[0] : header;
|
|
47
|
+
if (!token || !safeTokenEqual(token, secret)) {
|
|
48
|
+
response.writeHead(403, { 'Content-Type': 'application/json' });
|
|
49
|
+
response.end(JSON.stringify({ ok: false, description: 'Invalid secret token' }));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const rawBody = await readTextBody(request);
|
|
55
|
+
let update: TelegramUpdate;
|
|
56
|
+
try {
|
|
57
|
+
update = JSON.parse(rawBody) as TelegramUpdate;
|
|
58
|
+
} catch {
|
|
59
|
+
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
60
|
+
response.end(JSON.stringify({ ok: true }));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (handler.isOpen) {
|
|
65
|
+
handler.handleUpdate(update);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
69
|
+
response.end(JSON.stringify({ ok: true }));
|
|
70
|
+
} catch (error) {
|
|
71
|
+
logger.error('Telegram webhook error:', error);
|
|
72
|
+
response.writeHead(200, { 'Content-Type': 'application/json' });
|
|
73
|
+
response.end(JSON.stringify({ ok: true }));
|
|
74
|
+
}
|
|
75
|
+
}
|
package/client/Dashboard.tsx
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, useCallback } from 'react'
|
|
2
|
-
import { apiFetch } from './utils/api'
|
|
3
|
-
import { RefreshCw, Server, Wifi, WifiOff, Power, PowerOff, Loader2, Link2, BarChart3, ShieldCheck, Plus, X } from 'lucide-react'
|
|
4
|
-
|
|
5
|
-
interface BotInfo {
|
|
6
|
-
name: string
|
|
7
|
-
connected: boolean
|
|
8
|
-
mode: string
|
|
9
|
-
status: string
|
|
10
|
-
botInfo: { username: string; firstName: string } | null
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface Admin {
|
|
14
|
-
user_id: number
|
|
15
|
-
username: string
|
|
16
|
-
first_name: string
|
|
17
|
-
status: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type Tab = 'overview' | 'actions'
|
|
21
|
-
|
|
22
|
-
export default function TelegramDashboard() {
|
|
23
|
-
const [bots, setBots] = useState<BotInfo[]>([])
|
|
24
|
-
const [loading, setLoading] = useState(true)
|
|
25
|
-
const [error, setError] = useState('')
|
|
26
|
-
const [tab, setTab] = useState<Tab>('overview')
|
|
27
|
-
const [actionLoading, setActionLoading] = useState<Record<string, boolean>>({})
|
|
28
|
-
|
|
29
|
-
// Quick actions state
|
|
30
|
-
const [selectedBot, setSelectedBot] = useState('')
|
|
31
|
-
const [chatId, setChatId] = useState('')
|
|
32
|
-
const [inviteResult, setInviteResult] = useState('')
|
|
33
|
-
const [admins, setAdmins] = useState<Admin[]>([])
|
|
34
|
-
const [adminsLoading, setAdminsLoading] = useState(false)
|
|
35
|
-
|
|
36
|
-
// Poll state
|
|
37
|
-
const [pollQuestion, setPollQuestion] = useState('')
|
|
38
|
-
const [pollOptions, setPollOptions] = useState(['', ''])
|
|
39
|
-
const [pollAnonymous, setPollAnonymous] = useState(true)
|
|
40
|
-
const [pollMultiple, setPollMultiple] = useState(false)
|
|
41
|
-
const [pollResult, setPollResult] = useState('')
|
|
42
|
-
const [pollLoading, setPollLoading] = useState(false)
|
|
43
|
-
|
|
44
|
-
const fetchData = useCallback(async () => {
|
|
45
|
-
setLoading(true)
|
|
46
|
-
setError('')
|
|
47
|
-
try {
|
|
48
|
-
const res = await apiFetch('/api/telegram/bots')
|
|
49
|
-
const json = await res.json()
|
|
50
|
-
if (json.success) setBots(json.data)
|
|
51
|
-
else setError(json.error || '获取数据失败')
|
|
52
|
-
} catch {
|
|
53
|
-
setError('无法连接服务器')
|
|
54
|
-
} finally {
|
|
55
|
-
setLoading(false)
|
|
56
|
-
}
|
|
57
|
-
}, [])
|
|
58
|
-
|
|
59
|
-
useEffect(() => { fetchData() }, [fetchData])
|
|
60
|
-
|
|
61
|
-
const toggleConnect = async (name: string, connected: boolean) => {
|
|
62
|
-
setActionLoading(prev => ({ ...prev, [name]: true }))
|
|
63
|
-
try {
|
|
64
|
-
const endpoint = connected ? 'disconnect' : 'connect'
|
|
65
|
-
const res = await apiFetch(`/api/telegram/bots/${encodeURIComponent(name)}/${endpoint}`, { method: 'POST' })
|
|
66
|
-
const json = await res.json()
|
|
67
|
-
if (!json.success) setError(json.error || '操作失败')
|
|
68
|
-
await fetchData()
|
|
69
|
-
} catch {
|
|
70
|
-
setError('操作失败')
|
|
71
|
-
} finally {
|
|
72
|
-
setActionLoading(prev => ({ ...prev, [name]: false }))
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const createInvite = async () => {
|
|
77
|
-
if (!selectedBot || !chatId) return
|
|
78
|
-
setInviteResult('')
|
|
79
|
-
try {
|
|
80
|
-
const res = await apiFetch(`/api/telegram/bots/${encodeURIComponent(selectedBot)}/invite`, {
|
|
81
|
-
method: 'POST',
|
|
82
|
-
headers: { 'Content-Type': 'application/json' },
|
|
83
|
-
body: JSON.stringify({ chat_id: chatId }),
|
|
84
|
-
})
|
|
85
|
-
const json = await res.json()
|
|
86
|
-
if (json.success && json.data?.invite_link) setInviteResult(json.data.invite_link)
|
|
87
|
-
else setError(json.error || '创建失败')
|
|
88
|
-
} catch {
|
|
89
|
-
setError('创建邀请链接失败')
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const fetchAdmins = async () => {
|
|
94
|
-
if (!selectedBot || !chatId) return
|
|
95
|
-
setAdminsLoading(true)
|
|
96
|
-
setAdmins([])
|
|
97
|
-
try {
|
|
98
|
-
const res = await apiFetch(`/api/telegram/bots/${encodeURIComponent(selectedBot)}/admins?chat_id=${encodeURIComponent(chatId)}`)
|
|
99
|
-
const json = await res.json()
|
|
100
|
-
if (json.success && Array.isArray(json.data)) setAdmins(json.data)
|
|
101
|
-
else setError(json.error || '获取管理员失败')
|
|
102
|
-
} catch {
|
|
103
|
-
setError('获取管理员失败')
|
|
104
|
-
} finally {
|
|
105
|
-
setAdminsLoading(false)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const sendPoll = async () => {
|
|
110
|
-
if (!selectedBot || !chatId || !pollQuestion) return
|
|
111
|
-
const validOptions = pollOptions.filter(o => o.trim())
|
|
112
|
-
if (validOptions.length < 2) { setError('至少需要 2 个选项'); return }
|
|
113
|
-
setPollLoading(true)
|
|
114
|
-
setPollResult('')
|
|
115
|
-
try {
|
|
116
|
-
const res = await apiFetch(`/api/telegram/bots/${encodeURIComponent(selectedBot)}/poll`, {
|
|
117
|
-
method: 'POST',
|
|
118
|
-
headers: { 'Content-Type': 'application/json' },
|
|
119
|
-
body: JSON.stringify({ chat_id: chatId, question: pollQuestion, options: validOptions, is_anonymous: pollAnonymous, allows_multiple: pollMultiple }),
|
|
120
|
-
})
|
|
121
|
-
const json = await res.json()
|
|
122
|
-
if (json.success) setPollResult(`投票已发送 (ID: ${json.data?.message_id ?? '未知'})`)
|
|
123
|
-
else setError(json.error || '发送失败')
|
|
124
|
-
} catch {
|
|
125
|
-
setError('发送投票失败')
|
|
126
|
-
} finally {
|
|
127
|
-
setPollLoading(false)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const onlineBots = bots.filter(b => b.connected)
|
|
132
|
-
|
|
133
|
-
return (
|
|
134
|
-
<div className="p-6 max-w-5xl mx-auto">
|
|
135
|
-
<div className="flex items-center justify-between mb-6">
|
|
136
|
-
<h1 className="text-2xl font-bold flex items-center gap-2">
|
|
137
|
-
<Server className="w-6 h-6" /> Telegram 机器人
|
|
138
|
-
</h1>
|
|
139
|
-
<button onClick={fetchData} disabled={loading}
|
|
140
|
-
className="flex items-center gap-1 px-3 py-1.5 rounded bg-sky-500 text-white hover:bg-sky-600 disabled:opacity-50 text-sm">
|
|
141
|
-
<RefreshCw className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} /> 刷新
|
|
142
|
-
</button>
|
|
143
|
-
</div>
|
|
144
|
-
|
|
145
|
-
{error && <div className="mb-4 p-3 bg-red-50 text-red-600 rounded border border-red-200 flex items-center justify-between">
|
|
146
|
-
<span>{error}</span>
|
|
147
|
-
<button onClick={() => setError('')} className="text-red-400 hover:text-red-600"><X className="w-4 h-4" /></button>
|
|
148
|
-
</div>}
|
|
149
|
-
|
|
150
|
-
{/* Tabs */}
|
|
151
|
-
<div className="flex gap-1 mb-6 border-b">
|
|
152
|
-
<button onClick={() => setTab('overview')}
|
|
153
|
-
className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === 'overview' ? 'border-sky-500 text-sky-600' : 'border-transparent text-gray-500 hover:text-gray-700'}`}>
|
|
154
|
-
概览
|
|
155
|
-
</button>
|
|
156
|
-
<button onClick={() => setTab('actions')}
|
|
157
|
-
className={`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${tab === 'actions' ? 'border-sky-500 text-sky-600' : 'border-transparent text-gray-500 hover:text-gray-700'}`}>
|
|
158
|
-
快捷操作
|
|
159
|
-
</button>
|
|
160
|
-
</div>
|
|
161
|
-
|
|
162
|
-
{/* Overview Tab */}
|
|
163
|
-
{tab === 'overview' && (
|
|
164
|
-
<>
|
|
165
|
-
{!loading && !bots.length && !error && (
|
|
166
|
-
<div className="text-center text-gray-500 py-12">暂无 Telegram 机器人实例</div>
|
|
167
|
-
)}
|
|
168
|
-
<div className="grid gap-4 md:grid-cols-2">
|
|
169
|
-
{bots.map((bot) => (
|
|
170
|
-
<div key={bot.name} className="border rounded-lg p-4 bg-card shadow-sm">
|
|
171
|
-
<div className="flex items-center justify-between mb-3">
|
|
172
|
-
<span className="font-medium text-lg">{bot.name}</span>
|
|
173
|
-
{bot.connected
|
|
174
|
-
? <span className="flex items-center gap-1 text-green-600 text-sm"><Wifi className="w-4 h-4" /> 在线</span>
|
|
175
|
-
: <span className="flex items-center gap-1 text-gray-400 text-sm"><WifiOff className="w-4 h-4" /> 离线</span>}
|
|
176
|
-
</div>
|
|
177
|
-
{bot.botInfo && <div className="text-sm text-gray-500 mb-2">@{bot.botInfo.username} ({bot.botInfo.firstName})</div>}
|
|
178
|
-
<div className="text-sm text-gray-600 mb-3">
|
|
179
|
-
<div className="flex justify-between"><span>模式</span><span className="font-mono">{bot.mode}</span></div>
|
|
180
|
-
</div>
|
|
181
|
-
<button
|
|
182
|
-
onClick={() => toggleConnect(bot.name, bot.connected)}
|
|
183
|
-
disabled={actionLoading[bot.name]}
|
|
184
|
-
className={`flex items-center gap-1 px-3 py-1.5 rounded text-sm text-white ${bot.connected ? 'bg-red-500 hover:bg-red-600' : 'bg-green-500 hover:bg-green-600'} disabled:opacity-50`}>
|
|
185
|
-
{actionLoading[bot.name]
|
|
186
|
-
? <Loader2 className="w-3.5 h-3.5 animate-spin" />
|
|
187
|
-
: bot.connected ? <PowerOff className="w-3.5 h-3.5" /> : <Power className="w-3.5 h-3.5" />}
|
|
188
|
-
{bot.connected ? '断开' : '连接'}
|
|
189
|
-
</button>
|
|
190
|
-
</div>
|
|
191
|
-
))}
|
|
192
|
-
</div>
|
|
193
|
-
</>
|
|
194
|
-
)}
|
|
195
|
-
|
|
196
|
-
{/* Quick Actions Tab */}
|
|
197
|
-
{tab === 'actions' && (
|
|
198
|
-
<div className="space-y-6">
|
|
199
|
-
{/* Bot + Chat selector */}
|
|
200
|
-
<div className="flex flex-wrap items-end gap-3">
|
|
201
|
-
<div>
|
|
202
|
-
<label className="block text-xs text-gray-500 mb-1">机器人</label>
|
|
203
|
-
<select value={selectedBot} onChange={(e) => setSelectedBot(e.target.value)}
|
|
204
|
-
className="border rounded px-2 py-1.5 text-sm min-w-[140px]">
|
|
205
|
-
<option value="">--</option>
|
|
206
|
-
{onlineBots.map(b => <option key={b.name} value={b.name}>{b.name}</option>)}
|
|
207
|
-
</select>
|
|
208
|
-
</div>
|
|
209
|
-
<div>
|
|
210
|
-
<label className="block text-xs text-gray-500 mb-1">Chat ID</label>
|
|
211
|
-
<input value={chatId} onChange={(e) => setChatId(e.target.value)} placeholder="-100xxxxxxxxxx"
|
|
212
|
-
className="border rounded px-2 py-1.5 text-sm w-[180px]" />
|
|
213
|
-
</div>
|
|
214
|
-
</div>
|
|
215
|
-
|
|
216
|
-
{!onlineBots.length && <div className="text-center text-gray-500 py-4">暂无在线机器人</div>}
|
|
217
|
-
|
|
218
|
-
{selectedBot && chatId && (
|
|
219
|
-
<div className="grid gap-4 md:grid-cols-2">
|
|
220
|
-
{/* Invite Link */}
|
|
221
|
-
<div className="border rounded-lg p-4 bg-card shadow-sm">
|
|
222
|
-
<h3 className="font-medium flex items-center gap-2 mb-3"><Link2 className="w-4 h-4 text-sky-500" /> 创建邀请链接</h3>
|
|
223
|
-
<button onClick={createInvite} className="px-3 py-1.5 rounded bg-sky-500 text-white text-sm hover:bg-sky-600">
|
|
224
|
-
生成链接
|
|
225
|
-
</button>
|
|
226
|
-
{inviteResult && (
|
|
227
|
-
<div className="mt-2 p-2 bg-gray-50 rounded text-sm break-all">
|
|
228
|
-
<a href={inviteResult} target="_blank" rel="noreferrer" className="text-sky-600 hover:underline">{inviteResult}</a>
|
|
229
|
-
</div>
|
|
230
|
-
)}
|
|
231
|
-
</div>
|
|
232
|
-
|
|
233
|
-
{/* Admin List */}
|
|
234
|
-
<div className="border rounded-lg p-4 bg-card shadow-sm">
|
|
235
|
-
<h3 className="font-medium flex items-center gap-2 mb-3"><ShieldCheck className="w-4 h-4 text-sky-500" /> 管理员列表</h3>
|
|
236
|
-
<button onClick={fetchAdmins} disabled={adminsLoading}
|
|
237
|
-
className="px-3 py-1.5 rounded bg-sky-500 text-white text-sm hover:bg-sky-600 disabled:opacity-50 flex items-center gap-1">
|
|
238
|
-
{adminsLoading && <Loader2 className="w-3.5 h-3.5 animate-spin" />} 查询
|
|
239
|
-
</button>
|
|
240
|
-
{admins.length > 0 && (
|
|
241
|
-
<div className="mt-2 space-y-1">
|
|
242
|
-
{admins.map(a => (
|
|
243
|
-
<div key={a.user_id} className="flex items-center justify-between text-sm py-1 border-b last:border-0">
|
|
244
|
-
<span>{a.first_name} {a.username ? `(@${a.username})` : ''}</span>
|
|
245
|
-
<span className="text-xs text-gray-400">{a.status}</span>
|
|
246
|
-
</div>
|
|
247
|
-
))}
|
|
248
|
-
</div>
|
|
249
|
-
)}
|
|
250
|
-
</div>
|
|
251
|
-
|
|
252
|
-
{/* Send Poll */}
|
|
253
|
-
<div className="border rounded-lg p-4 bg-card shadow-sm md:col-span-2">
|
|
254
|
-
<h3 className="font-medium flex items-center gap-2 mb-3"><BarChart3 className="w-4 h-4 text-sky-500" /> 发起投票</h3>
|
|
255
|
-
<div className="space-y-2">
|
|
256
|
-
<input value={pollQuestion} onChange={(e) => setPollQuestion(e.target.value)} placeholder="投票问题"
|
|
257
|
-
className="border rounded px-2 py-1.5 text-sm w-full" />
|
|
258
|
-
{pollOptions.map((opt, i) => (
|
|
259
|
-
<div key={i} className="flex items-center gap-2">
|
|
260
|
-
<input value={opt} onChange={(e) => {
|
|
261
|
-
const next = [...pollOptions]; next[i] = e.target.value; setPollOptions(next)
|
|
262
|
-
}} placeholder={`选项 ${i + 1}`}
|
|
263
|
-
className="border rounded px-2 py-1.5 text-sm flex-1" />
|
|
264
|
-
{pollOptions.length > 2 && (
|
|
265
|
-
<button onClick={() => setPollOptions(pollOptions.filter((_, j) => j !== i))}
|
|
266
|
-
className="text-gray-400 hover:text-red-500"><X className="w-4 h-4" /></button>
|
|
267
|
-
)}
|
|
268
|
-
</div>
|
|
269
|
-
))}
|
|
270
|
-
<button onClick={() => setPollOptions([...pollOptions, ''])}
|
|
271
|
-
className="flex items-center gap-1 text-sm text-sky-500 hover:text-sky-600">
|
|
272
|
-
<Plus className="w-3.5 h-3.5" /> 添加选项
|
|
273
|
-
</button>
|
|
274
|
-
<div className="flex items-center gap-4 text-sm text-gray-600">
|
|
275
|
-
<label className="flex items-center gap-1">
|
|
276
|
-
<input type="checkbox" checked={pollAnonymous} onChange={(e) => setPollAnonymous(e.target.checked)} /> 匿名
|
|
277
|
-
</label>
|
|
278
|
-
<label className="flex items-center gap-1">
|
|
279
|
-
<input type="checkbox" checked={pollMultiple} onChange={(e) => setPollMultiple(e.target.checked)} /> 多选
|
|
280
|
-
</label>
|
|
281
|
-
</div>
|
|
282
|
-
<button onClick={sendPoll} disabled={pollLoading || !pollQuestion}
|
|
283
|
-
className="px-3 py-1.5 rounded bg-sky-500 text-white text-sm hover:bg-sky-600 disabled:opacity-50 flex items-center gap-1">
|
|
284
|
-
{pollLoading && <Loader2 className="w-3.5 h-3.5 animate-spin" />} 发送投票
|
|
285
|
-
</button>
|
|
286
|
-
{pollResult && <div className="text-sm text-green-600">{pollResult}</div>}
|
|
287
|
-
</div>
|
|
288
|
-
</div>
|
|
289
|
-
</div>
|
|
290
|
-
)}
|
|
291
|
-
</div>
|
|
292
|
-
)}
|
|
293
|
-
</div>
|
|
294
|
-
)
|
|
295
|
-
}
|
package/client/index.tsx
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { PluginRegisterHostApi } from '@zhin.js/console-types'
|
|
2
|
-
import TelegramDashboard from './Dashboard'
|
|
3
|
-
|
|
4
|
-
export function register(api: PluginRegisterHostApi) {
|
|
5
|
-
api.addRoute({
|
|
6
|
-
path: '/console/telegram',
|
|
7
|
-
name: 'Telegram',
|
|
8
|
-
element: api.React.createElement(TelegramDashboard, { hostReact: api.React }),
|
|
9
|
-
})
|
|
10
|
-
api.addTool({ id: 'telegram', name: 'Telegram', path: '/console/telegram' })
|
|
11
|
-
}
|
package/client/tsconfig.json
DELETED
package/client/utils/api.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const TOKEN_KEY = "zhin_api_token";
|
|
2
|
-
|
|
3
|
-
export function getToken(): string | null {
|
|
4
|
-
return localStorage.getItem(TOKEN_KEY);
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export async function apiFetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
|
8
|
-
const token = getToken();
|
|
9
|
-
const headers = new Headers(init?.headers);
|
|
10
|
-
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
11
|
-
const res = await fetch(input, { ...init, headers });
|
|
12
|
-
if (res.status === 401) {
|
|
13
|
-
localStorage.removeItem(TOKEN_KEY);
|
|
14
|
-
window.dispatchEvent(new CustomEvent("zhin:auth-required"));
|
|
15
|
-
}
|
|
16
|
-
return res;
|
|
17
|
-
}
|
package/dist/index.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import{useEffect as Ue,useState as r,useCallback as Oe}from"react";var oe="zhin_api_token";function xe(){return localStorage.getItem(oe)}async function g(o,l){let f=xe(),i=new Headers(l?.headers);f&&i.set("Authorization",`Bearer ${f}`);let p=await fetch(o,{...l,headers:i});return p.status===401&&(localStorage.removeItem(oe),window.dispatchEvent(new CustomEvent("zhin:auth-required"))),p}import{forwardRef as ke,createElement as we}from"react";var G=(...o)=>o.filter((l,f,i)=>!!l&&l.trim()!==""&&i.indexOf(l)===f).join(" ").trim();var ue=o=>o.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();var de=o=>o.replace(/^([A-Z])|[\s-_]+(\w)/g,(l,f,i)=>i?i.toUpperCase():f.toLowerCase());var z=o=>{let l=de(o);return l.charAt(0).toUpperCase()+l.slice(1)};import{forwardRef as Se,createElement as fe}from"react";var W={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};var le=o=>{for(let l in o)if(l.startsWith("aria-")||l==="role"||l==="title")return!0;return!1};import{createContext as Ce,useContext as he,useMemo as Qe,createElement as Je}from"react";var ge=Ce({});var se=()=>he(ge);var re=Se(({color:o,size:l,strokeWidth:f,absoluteStrokeWidth:i,className:p="",children:s,iconNode:x,...k},q)=>{let{size:C=24,strokeWidth:n=2,absoluteStrokeWidth:V=!1,color:m="currentColor",className:E=""}=se()??{},w=i??V?Number(f??n)*24/Number(l??C):f??n;return fe("svg",{ref:q,...W,width:l??C??W.width,height:l??C??W.height,stroke:o??m,strokeWidth:w,className:G("lucide",E,p),...!s&&!le(k)&&{"aria-hidden":"true"},...k},[...x.map(([v,U])=>fe(v,U)),...Array.isArray(s)?s:[s]])});var u=(o,l)=>{let f=ke(({className:i,...p},s)=>we(re,{ref:s,iconNode:l,className:G(`lucide-${ue(z(o))}`,`lucide-${o}`,i),...p}));return f.displayName=z(o),f};var Pe=[["path",{d:"M3 3v16a2 2 0 0 0 2 2h16",key:"c24i48"}],["path",{d:"M18 17V9",key:"2bz60n"}],["path",{d:"M13 17V5",key:"1frdt8"}],["path",{d:"M8 17v-3",key:"17ska0"}]],I=u("chart-column",Pe);var Ae=[["path",{d:"M9 17H7A5 5 0 0 1 7 7h2",key:"8i5ue5"}],["path",{d:"M15 7h2a5 5 0 1 1 0 10h-2",key:"1b9ql8"}],["line",{x1:"8",x2:"16",y1:"12",y2:"12",key:"1jonct"}]],A=u("link-2",Ae);var Be=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],L=u("loader-circle",Be);var Me=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]],B=u("plus",Me);var Fe=[["path",{d:"M18.36 6.64A9 9 0 0 1 20.77 15",key:"dxknvb"}],["path",{d:"M6.16 6.16a9 9 0 1 0 12.68 12.68",key:"1x7qb5"}],["path",{d:"M12 2v4",key:"3427ic"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],M=u("power-off",Fe);var De=[["path",{d:"M12 2v10",key:"mnfbl"}],["path",{d:"M18.4 6.6a9 9 0 1 1-12.77.04",key:"obofu9"}]],F=u("power",De);var ye=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],D=u("refresh-cw",ye);var Re=[["rect",{width:"20",height:"8",x:"2",y:"2",rx:"2",ry:"2",key:"ngkwjq"}],["rect",{width:"20",height:"8",x:"2",y:"14",rx:"2",ry:"2",key:"iecqi9"}],["line",{x1:"6",x2:"6.01",y1:"6",y2:"6",key:"16zg32"}],["line",{x1:"6",x2:"6.01",y1:"18",y2:"18",key:"nzw8ys"}]],y=u("server",Re);var Te=[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],R=u("shield-check",Te);var be=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}],["path",{d:"M5 12.859a10 10 0 0 1 5.17-2.69",key:"1dl1wf"}],["path",{d:"M19 12.859a10 10 0 0 0-2.007-1.523",key:"4k23kn"}],["path",{d:"M2 8.82a15 15 0 0 1 4.177-2.643",key:"1grhjp"}],["path",{d:"M22 8.82a15 15 0 0 0-11.288-3.764",key:"z3jwby"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],T=u("wifi-off",be);var qe=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],b=u("wifi",qe);var ve=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],S=u("x",ve);import{Fragment as He,jsx as a,jsxs as t}from"react/jsx-runtime";function X(){let[o,l]=r([]),[f,i]=r(!0),[p,s]=r(""),[x,k]=r("overview"),[q,C]=r({}),[n,V]=r(""),[m,E]=r(""),[w,v]=r(""),[U,K]=r([]),[Z,Q]=r(!1),[O,ie]=r(""),[h,N]=r(["",""]),[J,ce]=r(!0),[_,ne]=r(!1),[j,$]=r(""),[Y,ee]=r(!1),H=Oe(async()=>{i(!0),s("");try{let d=await(await g("/api/telegram/bots")).json();d.success?l(d.data):s(d.error||"\u83B7\u53D6\u6570\u636E\u5931\u8D25")}catch{s("\u65E0\u6CD5\u8FDE\u63A5\u670D\u52A1\u5668")}finally{i(!1)}},[]);Ue(()=>{H()},[H]);let pe=async(e,d)=>{C(c=>({...c,[e]:!0}));try{let c=d?"disconnect":"connect",te=await(await g(`/api/telegram/bots/${encodeURIComponent(e)}/${c}`,{method:"POST"})).json();te.success||s(te.error||"\u64CD\u4F5C\u5931\u8D25"),await H()}catch{s("\u64CD\u4F5C\u5931\u8D25")}finally{C(c=>({...c,[e]:!1}))}},me=async()=>{if(!(!n||!m)){v("");try{let d=await(await g(`/api/telegram/bots/${encodeURIComponent(n)}/invite`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({chat_id:m})})).json();d.success&&d.data?.invite_link?v(d.data.invite_link):s(d.error||"\u521B\u5EFA\u5931\u8D25")}catch{s("\u521B\u5EFA\u9080\u8BF7\u94FE\u63A5\u5931\u8D25")}}},Le=async()=>{if(!(!n||!m)){Q(!0),K([]);try{let d=await(await g(`/api/telegram/bots/${encodeURIComponent(n)}/admins?chat_id=${encodeURIComponent(m)}`)).json();d.success&&Array.isArray(d.data)?K(d.data):s(d.error||"\u83B7\u53D6\u7BA1\u7406\u5458\u5931\u8D25")}catch{s("\u83B7\u53D6\u7BA1\u7406\u5458\u5931\u8D25")}finally{Q(!1)}}},Ie=async()=>{if(!n||!m||!O)return;let e=h.filter(d=>d.trim());if(e.length<2){s("\u81F3\u5C11\u9700\u8981 2 \u4E2A\u9009\u9879");return}ee(!0),$("");try{let c=await(await g(`/api/telegram/bots/${encodeURIComponent(n)}/poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({chat_id:m,question:O,options:e,is_anonymous:J,allows_multiple:_})})).json();c.success?$(`\u6295\u7968\u5DF2\u53D1\u9001 (ID: ${c.data?.message_id??"\u672A\u77E5"})`):s(c.error||"\u53D1\u9001\u5931\u8D25")}catch{s("\u53D1\u9001\u6295\u7968\u5931\u8D25")}finally{ee(!1)}},ae=o.filter(e=>e.connected);return t("div",{className:"p-6 max-w-5xl mx-auto",children:[t("div",{className:"flex items-center justify-between mb-6",children:[t("h1",{className:"text-2xl font-bold flex items-center gap-2",children:[a(y,{className:"w-6 h-6"})," Telegram \u673A\u5668\u4EBA"]}),t("button",{onClick:H,disabled:f,className:"flex items-center gap-1 px-3 py-1.5 rounded bg-sky-500 text-white hover:bg-sky-600 disabled:opacity-50 text-sm",children:[a(D,{className:`w-4 h-4 ${f?"animate-spin":""}`})," \u5237\u65B0"]})]}),p&&t("div",{className:"mb-4 p-3 bg-red-50 text-red-600 rounded border border-red-200 flex items-center justify-between",children:[a("span",{children:p}),a("button",{onClick:()=>s(""),className:"text-red-400 hover:text-red-600",children:a(S,{className:"w-4 h-4"})})]}),t("div",{className:"flex gap-1 mb-6 border-b",children:[a("button",{onClick:()=>k("overview"),className:`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${x==="overview"?"border-sky-500 text-sky-600":"border-transparent text-gray-500 hover:text-gray-700"}`,children:"\u6982\u89C8"}),a("button",{onClick:()=>k("actions"),className:`px-4 py-2 text-sm font-medium border-b-2 transition-colors ${x==="actions"?"border-sky-500 text-sky-600":"border-transparent text-gray-500 hover:text-gray-700"}`,children:"\u5FEB\u6377\u64CD\u4F5C"})]}),x==="overview"&&t(He,{children:[!f&&!o.length&&!p&&a("div",{className:"text-center text-gray-500 py-12",children:"\u6682\u65E0 Telegram \u673A\u5668\u4EBA\u5B9E\u4F8B"}),a("div",{className:"grid gap-4 md:grid-cols-2",children:o.map(e=>t("div",{className:"border rounded-lg p-4 bg-card shadow-sm",children:[t("div",{className:"flex items-center justify-between mb-3",children:[a("span",{className:"font-medium text-lg",children:e.name}),e.connected?t("span",{className:"flex items-center gap-1 text-green-600 text-sm",children:[a(b,{className:"w-4 h-4"})," \u5728\u7EBF"]}):t("span",{className:"flex items-center gap-1 text-gray-400 text-sm",children:[a(T,{className:"w-4 h-4"})," \u79BB\u7EBF"]})]}),e.botInfo&&t("div",{className:"text-sm text-gray-500 mb-2",children:["@",e.botInfo.username," (",e.botInfo.firstName,")"]}),a("div",{className:"text-sm text-gray-600 mb-3",children:t("div",{className:"flex justify-between",children:[a("span",{children:"\u6A21\u5F0F"}),a("span",{className:"font-mono",children:e.mode})]})}),t("button",{onClick:()=>pe(e.name,e.connected),disabled:q[e.name],className:`flex items-center gap-1 px-3 py-1.5 rounded text-sm text-white ${e.connected?"bg-red-500 hover:bg-red-600":"bg-green-500 hover:bg-green-600"} disabled:opacity-50`,children:[q[e.name]?a(L,{className:"w-3.5 h-3.5 animate-spin"}):e.connected?a(M,{className:"w-3.5 h-3.5"}):a(F,{className:"w-3.5 h-3.5"}),e.connected?"\u65AD\u5F00":"\u8FDE\u63A5"]})]},e.name))})]}),x==="actions"&&t("div",{className:"space-y-6",children:[t("div",{className:"flex flex-wrap items-end gap-3",children:[t("div",{children:[a("label",{className:"block text-xs text-gray-500 mb-1",children:"\u673A\u5668\u4EBA"}),t("select",{value:n,onChange:e=>V(e.target.value),className:"border rounded px-2 py-1.5 text-sm min-w-[140px]",children:[a("option",{value:"",children:"--"}),ae.map(e=>a("option",{value:e.name,children:e.name},e.name))]})]}),t("div",{children:[a("label",{className:"block text-xs text-gray-500 mb-1",children:"Chat ID"}),a("input",{value:m,onChange:e=>E(e.target.value),placeholder:"-100xxxxxxxxxx",className:"border rounded px-2 py-1.5 text-sm w-[180px]"})]})]}),!ae.length&&a("div",{className:"text-center text-gray-500 py-4",children:"\u6682\u65E0\u5728\u7EBF\u673A\u5668\u4EBA"}),n&&m&&t("div",{className:"grid gap-4 md:grid-cols-2",children:[t("div",{className:"border rounded-lg p-4 bg-card shadow-sm",children:[t("h3",{className:"font-medium flex items-center gap-2 mb-3",children:[a(A,{className:"w-4 h-4 text-sky-500"})," \u521B\u5EFA\u9080\u8BF7\u94FE\u63A5"]}),a("button",{onClick:me,className:"px-3 py-1.5 rounded bg-sky-500 text-white text-sm hover:bg-sky-600",children:"\u751F\u6210\u94FE\u63A5"}),w&&a("div",{className:"mt-2 p-2 bg-gray-50 rounded text-sm break-all",children:a("a",{href:w,target:"_blank",rel:"noreferrer",className:"text-sky-600 hover:underline",children:w})})]}),t("div",{className:"border rounded-lg p-4 bg-card shadow-sm",children:[t("h3",{className:"font-medium flex items-center gap-2 mb-3",children:[a(R,{className:"w-4 h-4 text-sky-500"})," \u7BA1\u7406\u5458\u5217\u8868"]}),t("button",{onClick:Le,disabled:Z,className:"px-3 py-1.5 rounded bg-sky-500 text-white text-sm hover:bg-sky-600 disabled:opacity-50 flex items-center gap-1",children:[Z&&a(L,{className:"w-3.5 h-3.5 animate-spin"})," \u67E5\u8BE2"]}),U.length>0&&a("div",{className:"mt-2 space-y-1",children:U.map(e=>t("div",{className:"flex items-center justify-between text-sm py-1 border-b last:border-0",children:[t("span",{children:[e.first_name," ",e.username?`(@${e.username})`:""]}),a("span",{className:"text-xs text-gray-400",children:e.status})]},e.user_id))})]}),t("div",{className:"border rounded-lg p-4 bg-card shadow-sm md:col-span-2",children:[t("h3",{className:"font-medium flex items-center gap-2 mb-3",children:[a(I,{className:"w-4 h-4 text-sky-500"})," \u53D1\u8D77\u6295\u7968"]}),t("div",{className:"space-y-2",children:[a("input",{value:O,onChange:e=>ie(e.target.value),placeholder:"\u6295\u7968\u95EE\u9898",className:"border rounded px-2 py-1.5 text-sm w-full"}),h.map((e,d)=>t("div",{className:"flex items-center gap-2",children:[a("input",{value:e,onChange:c=>{let P=[...h];P[d]=c.target.value,N(P)},placeholder:`\u9009\u9879 ${d+1}`,className:"border rounded px-2 py-1.5 text-sm flex-1"}),h.length>2&&a("button",{onClick:()=>N(h.filter((c,P)=>P!==d)),className:"text-gray-400 hover:text-red-500",children:a(S,{className:"w-4 h-4"})})]},d)),t("button",{onClick:()=>N([...h,""]),className:"flex items-center gap-1 text-sm text-sky-500 hover:text-sky-600",children:[a(B,{className:"w-3.5 h-3.5"})," \u6DFB\u52A0\u9009\u9879"]}),t("div",{className:"flex items-center gap-4 text-sm text-gray-600",children:[t("label",{className:"flex items-center gap-1",children:[a("input",{type:"checkbox",checked:J,onChange:e=>ce(e.target.checked)})," \u533F\u540D"]}),t("label",{className:"flex items-center gap-1",children:[a("input",{type:"checkbox",checked:_,onChange:e=>ne(e.target.checked)})," \u591A\u9009"]})]}),t("button",{onClick:Ie,disabled:Y||!O,className:"px-3 py-1.5 rounded bg-sky-500 text-white text-sm hover:bg-sky-600 disabled:opacity-50 flex items-center gap-1",children:[Y&&a(L,{className:"w-3.5 h-3.5 animate-spin"})," \u53D1\u9001\u6295\u7968"]}),j&&a("div",{className:"text-sm text-green-600",children:j})]})]})]})]})]})}function $a(o){o.addRoute({path:"/console/telegram",name:"Telegram",element:o.React.createElement(X,{hostReact:o.React})}),o.addTool({id:"telegram",name:"Telegram",path:"/console/telegram"})}export{$a as register};
|
|
2
|
-
/*! Bundled license information:
|
|
3
|
-
|
|
4
|
-
lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs:
|
|
5
|
-
lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs:
|
|
6
|
-
lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs:
|
|
7
|
-
lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs:
|
|
8
|
-
lucide-react/dist/esm/defaultAttributes.mjs:
|
|
9
|
-
lucide-react/dist/esm/shared/src/utils/hasA11yProp.mjs:
|
|
10
|
-
lucide-react/dist/esm/context.mjs:
|
|
11
|
-
lucide-react/dist/esm/Icon.mjs:
|
|
12
|
-
lucide-react/dist/esm/createLucideIcon.mjs:
|
|
13
|
-
lucide-react/dist/esm/icons/chart-column.mjs:
|
|
14
|
-
lucide-react/dist/esm/icons/link-2.mjs:
|
|
15
|
-
lucide-react/dist/esm/icons/loader-circle.mjs:
|
|
16
|
-
lucide-react/dist/esm/icons/plus.mjs:
|
|
17
|
-
lucide-react/dist/esm/icons/power-off.mjs:
|
|
18
|
-
lucide-react/dist/esm/icons/power.mjs:
|
|
19
|
-
lucide-react/dist/esm/icons/refresh-cw.mjs:
|
|
20
|
-
lucide-react/dist/esm/icons/server.mjs:
|
|
21
|
-
lucide-react/dist/esm/icons/shield-check.mjs:
|
|
22
|
-
lucide-react/dist/esm/icons/wifi-off.mjs:
|
|
23
|
-
lucide-react/dist/esm/icons/wifi.mjs:
|
|
24
|
-
lucide-react/dist/esm/icons/x.mjs:
|
|
25
|
-
lucide-react/dist/esm/lucide-react.mjs:
|
|
26
|
-
(**
|
|
27
|
-
* @license lucide-react v1.14.0 - ISC
|
|
28
|
-
*
|
|
29
|
-
* This source code is licensed under the ISC license.
|
|
30
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
31
|
-
*)
|
|
32
|
-
*/
|
package/lib/adapter.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telegram 适配器
|
|
3
|
-
*/
|
|
4
|
-
import { Adapter, Plugin } from "zhin.js";
|
|
5
|
-
import { TelegramBot } from "./bot.js";
|
|
6
|
-
import type { TelegramBotConfig } from "./types.js";
|
|
7
|
-
export declare class TelegramAdapter extends Adapter<TelegramBot> {
|
|
8
|
-
constructor(plugin: Plugin);
|
|
9
|
-
createBot(config: TelegramBotConfig): TelegramBot;
|
|
10
|
-
kickMember(botId: string, sceneId: string, userId: string): Promise<boolean>;
|
|
11
|
-
unbanMember(botId: string, sceneId: string, userId: string): Promise<boolean>;
|
|
12
|
-
muteMember(botId: string, sceneId: string, userId: string, duration?: number): Promise<boolean>;
|
|
13
|
-
setAdmin(botId: string, sceneId: string, userId: string, enable?: boolean): Promise<boolean>;
|
|
14
|
-
setGroupName(botId: string, sceneId: string, name: string): Promise<boolean>;
|
|
15
|
-
getGroupInfo(botId: string, sceneId: string): Promise<any>;
|
|
16
|
-
start(): Promise<void>;
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=adapter.d.ts.map
|
package/lib/adapter.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,OAAO,EACP,MAAM,EACP,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,qBAAa,eAAgB,SAAQ,OAAO,CAAC,WAAW,CAAC;gBAC3C,MAAM,EAAE,MAAM;IAI1B,SAAS,CAAC,MAAM,EAAE,iBAAiB,GAAG,WAAW;IAM3C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAMzD,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAM1D,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAM;IAMzE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAO;IAMtE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAMzD,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAQ3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
package/lib/adapter.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Telegram 适配器
|
|
3
|
-
*/
|
|
4
|
-
import { Adapter, } from "zhin.js";
|
|
5
|
-
import { TelegramBot } from "./bot.js";
|
|
6
|
-
export class TelegramAdapter extends Adapter {
|
|
7
|
-
constructor(plugin) {
|
|
8
|
-
super(plugin, "telegram", []);
|
|
9
|
-
}
|
|
10
|
-
createBot(config) {
|
|
11
|
-
return new TelegramBot(this, config);
|
|
12
|
-
}
|
|
13
|
-
// ── IGroupManagement 标准群管方法 ──────────────────────────────────
|
|
14
|
-
async kickMember(botId, sceneId, userId) {
|
|
15
|
-
const bot = this.bots.get(botId);
|
|
16
|
-
if (!bot)
|
|
17
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
18
|
-
return bot.kickMember(Number(sceneId), Number(userId));
|
|
19
|
-
}
|
|
20
|
-
async unbanMember(botId, sceneId, userId) {
|
|
21
|
-
const bot = this.bots.get(botId);
|
|
22
|
-
if (!bot)
|
|
23
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
24
|
-
return bot.unbanMember(Number(sceneId), Number(userId));
|
|
25
|
-
}
|
|
26
|
-
async muteMember(botId, sceneId, userId, duration = 600) {
|
|
27
|
-
const bot = this.bots.get(botId);
|
|
28
|
-
if (!bot)
|
|
29
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
30
|
-
return bot.muteMember(Number(sceneId), Number(userId), duration);
|
|
31
|
-
}
|
|
32
|
-
async setAdmin(botId, sceneId, userId, enable = true) {
|
|
33
|
-
const bot = this.bots.get(botId);
|
|
34
|
-
if (!bot)
|
|
35
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
36
|
-
return bot.setAdmin(Number(sceneId), Number(userId), enable);
|
|
37
|
-
}
|
|
38
|
-
async setGroupName(botId, sceneId, name) {
|
|
39
|
-
const bot = this.bots.get(botId);
|
|
40
|
-
if (!bot)
|
|
41
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
42
|
-
return bot.setChatTitle(Number(sceneId), name);
|
|
43
|
-
}
|
|
44
|
-
async getGroupInfo(botId, sceneId) {
|
|
45
|
-
const bot = this.bots.get(botId);
|
|
46
|
-
if (!bot)
|
|
47
|
-
throw new Error(`Bot ${botId} 不存在`);
|
|
48
|
-
return bot.getChatInfo(Number(sceneId));
|
|
49
|
-
}
|
|
50
|
-
// ── 生命周期 ───────────────────────────────────────────────────────
|
|
51
|
-
async start() {
|
|
52
|
-
await super.start();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
//# sourceMappingURL=adapter.js.map
|
package/lib/adapter.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,OAAO,GAER,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGvC,MAAM,OAAO,eAAgB,SAAQ,OAAoB;IACvD,YAAY,MAAc;QACxB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;IAChC,CAAC;IAED,SAAS,CAAC,MAAyB;QACjC,OAAO,IAAI,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAED,gEAAgE;IAEhE,KAAK,CAAC,UAAU,CAAC,KAAa,EAAE,OAAe,EAAE,MAAc;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAa,EAAE,OAAe,EAAE,MAAc;QAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAa,EAAE,OAAe,EAAE,MAAc,EAAE,QAAQ,GAAG,GAAG;QAC7E,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,OAAe,EAAE,MAAc,EAAE,MAAM,GAAG,IAAI;QAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,OAAe,EAAE,IAAY;QAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,KAAa,EAAE,OAAe;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,kEAAkE;IAElE,KAAK,CAAC,KAAK;QACT,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;CACF"}
|