Simplify install with one-click scripts; honor HTTP(S)_PROXY for Telegram.

Add install.ps1/install.sh, shrink README to script-first flow, register bot commands, and route API calls through undici EnvHttpProxyAgent when a proxy is set (v0.2.2).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
owo
2026-08-14 17:46:01 +08:00
co-authored by Cursor
parent 8ef1622822
commit a83af2f33c
15 changed files with 1255 additions and 204 deletions
+12
View File
@@ -87,9 +87,21 @@ export class TelegramBridge {
this.ctx.logger.error(this.redact(err))
})
})
void this.client.setMyCommands([
{ command: 'start', description: '欢迎与用法' },
{ command: 'sessions', description: '列出并附着本机 live 会话' },
{ command: 'status', description: '查看当前绑定' },
{ command: 'unbind', description: '断开手机绑定(不关闭本机会话)' },
{ command: 'help', description: '显示帮助' },
]).then(() => {
this.ctx.logger.info('dsh-telegram-channel: bot commands registered')
}).catch((err) => {
this.ctx.logger.warn(`dsh-telegram-channel: setMyCommands failed: ${this.redact(err)}`)
})
if (!this.polling) {
this.polling = true
this.pollAbort = new AbortController()
this.ctx.logger.info('dsh-telegram-channel: long-polling started')
this.pollPromise = this.pollLoop()
}
}
+38 -1
View File
@@ -1,3 +1,5 @@
import { EnvHttpProxyAgent, fetch as undiciFetch } from 'undici'
export interface TelegramUser {
id: number
is_bot?: boolean
@@ -42,6 +44,11 @@ export interface InlineKeyboardMarkup {
inline_keyboard: InlineKeyboardButton[][]
}
export interface TelegramBotCommand {
command: string
description: string
}
export interface TelegramClientOptions {
fetch?: typeof fetch
baseUrl?: string
@@ -59,6 +66,32 @@ export interface TelegramClientLike {
): Promise<TelegramMessage>
sendChatAction(chatId: number, action: string): Promise<boolean>
answerCallbackQuery(callbackQueryId: string, text?: string): Promise<boolean>
setMyCommands(commands: TelegramBotCommand[]): Promise<boolean>
}
function resolveProxyUrl(): string | undefined {
return (
process.env.HTTPS_PROXY
|| process.env.HTTP_PROXY
|| process.env.https_proxy
|| process.env.http_proxy
|| undefined
)
}
/**
* Node's global `fetch` ignores HTTP(S)_PROXY unless `NODE_USE_ENV_PROXY=1`.
* Undici's EnvHttpProxyAgent honors the env vars (and NO_PROXY).
*/
function createDefaultFetch(): typeof fetch {
if (!resolveProxyUrl()) return globalThis.fetch
const agent = new EnvHttpProxyAgent()
const proxied = ((input: RequestInfo | URL, init?: RequestInit) =>
undiciFetch(input as string | URL, {
...(init as Record<string, unknown>),
dispatcher: agent,
})) as unknown as typeof fetch
return proxied
}
export class TelegramClient implements TelegramClientLike {
@@ -72,7 +105,7 @@ export class TelegramClient implements TelegramClientLike {
throw new Error('bot token is required')
}
this.token = token
this.fetchImpl = options.fetch ?? fetch
this.fetchImpl = options.fetch ?? createDefaultFetch()
this.baseUrl = options.baseUrl ?? 'https://api.telegram.org'
this.pollingTimeoutSec = options.pollingTimeoutSec ?? 30
}
@@ -143,4 +176,8 @@ export class TelegramClient implements TelegramClientLike {
if (text !== undefined) body.text = text
return this.call<boolean>('answerCallbackQuery', body)
}
async setMyCommands(commands: TelegramBotCommand[]): Promise<boolean> {
return this.call<boolean>('setMyCommands', { commands })
}
}
+14 -1
View File
@@ -21,6 +21,19 @@ export const Config: Schema<TelegramChannelConfig> = Schema.object({
pollingTimeoutSec: Schema.number().default(30),
})
function resolveAllowedUserIds(config: TelegramChannelConfig): number[] {
if (config.allowedUserIds && config.allowedUserIds.length > 0) {
return config.allowedUserIds
}
const raw = process.env.DSH_TELEGRAM_ALLOWED_USER_IDS ?? ''
return raw
.split(/[,;\s]+/)
.map((part) => part.trim())
.filter(Boolean)
.map((part) => Number(part))
.filter((n) => Number.isFinite(n) && n > 0)
}
export function apply(ctx: Context, config: TelegramChannelConfig): void {
const token = (config.token && config.token.length > 0)
? config.token
@@ -33,7 +46,7 @@ export function apply(ctx: Context, config: TelegramChannelConfig): void {
}
const bridge = new TelegramBridge(ctx, {
token,
allowedUserIds: config.allowedUserIds ?? [],
allowedUserIds: resolveAllowedUserIds(config),
allowAllUsers: config.allowAllUsers ?? false,
maxMessageLength: config.maxMessageLength ?? 4096,
pollingTimeoutSec: config.pollingTimeoutSec ?? 30,