From cb6e340c08f85e39bcb5b88da8b4b7642506f4a6 Mon Sep 17 00:00:00 2001 From: whhphd Date: Sun, 15 Mar 2026 01:47:44 +0800 Subject: [PATCH] feat(notify): add proxy support for Telegram notifications Telegram API (api.telegram.org) is blocked in some regions (e.g. China). This adds optional proxy support so users can send notifications via a local proxy without requiring system-wide TUN/VPN. Changes: - Add optional `proxy` field to Telegram notify channel schema - Use undici ProxyAgent when proxy is configured - Fall back to HTTPS_PROXY/HTTP_PROXY environment variables - Add undici as explicit dependency (bundled in Node 20+ but needed for types) Usage in inkos.json: { "type": "telegram", "botToken": "...", "chatId": "...", "proxy": "http://127.0.0.1:7890" } Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/core/package.json | 1 + packages/core/src/models/project.ts | 1 + packages/core/src/notify/dispatcher.ts | 2 +- packages/core/src/notify/telegram.ts | 20 ++++++++++++++++++-- pnpm-lock.yaml | 9 +++++++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 4155963b..553660e4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -34,6 +34,7 @@ "@anthropic-ai/sdk": "^0.78.0", "js-yaml": "^4.1.1", "openai": "^4.80.0", + "undici": "^7.24.2", "zod": "^3.24.0" }, "devDependencies": { diff --git a/packages/core/src/models/project.ts b/packages/core/src/models/project.ts index ab3d4847..fe3684fd 100644 --- a/packages/core/src/models/project.ts +++ b/packages/core/src/models/project.ts @@ -18,6 +18,7 @@ export const NotifyChannelSchema = z.discriminatedUnion("type", [ type: z.literal("telegram"), botToken: z.string().min(1), chatId: z.string().min(1), + proxy: z.string().optional(), }), z.object({ type: z.literal("wechat-work"), diff --git a/packages/core/src/notify/dispatcher.ts b/packages/core/src/notify/dispatcher.ts index d5e05dd4..4c9a8a06 100644 --- a/packages/core/src/notify/dispatcher.ts +++ b/packages/core/src/notify/dispatcher.ts @@ -20,7 +20,7 @@ export async function dispatchNotification( switch (channel.type) { case "telegram": await sendTelegram( - { botToken: channel.botToken, chatId: channel.chatId }, + { botToken: channel.botToken, chatId: channel.chatId, proxy: channel.proxy }, fullText, ); break; diff --git a/packages/core/src/notify/telegram.ts b/packages/core/src/notify/telegram.ts index e5141bf1..4cebe23d 100644 --- a/packages/core/src/notify/telegram.ts +++ b/packages/core/src/notify/telegram.ts @@ -1,6 +1,9 @@ +import { ProxyAgent } from "undici"; + export interface TelegramConfig { readonly botToken: string; readonly chatId: string; + readonly proxy?: string; } export async function sendTelegram( @@ -8,7 +11,14 @@ export async function sendTelegram( message: string, ): Promise { const url = `https://api.telegram.org/bot${config.botToken}/sendMessage`; - const response = await fetch(url, { + const proxyUrl = + config.proxy || + process.env.HTTPS_PROXY || + process.env.https_proxy || + process.env.HTTP_PROXY || + process.env.http_proxy; + + const fetchOptions: Record = { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ @@ -16,7 +26,13 @@ export async function sendTelegram( text: message, parse_mode: "Markdown", }), - }); + }; + + if (proxyUrl) { + fetchOptions.dispatcher = new ProxyAgent(proxyUrl); + } + + const response = await fetch(url, fetchOptions as RequestInit); if (!response.ok) { const body = await response.text(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d4632c49..ca50bd70 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: openai: specifier: ^4.80.0 version: 4.104.0(zod@3.25.76) + undici: + specifier: ^7.24.2 + version: 7.24.2 zod: specifier: ^3.24.0 version: 3.25.76 @@ -715,6 +718,10 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@7.24.2: + resolution: {integrity: sha512-P9J1HWYV/ajFr8uCqk5QixwiRKmB1wOamgS0e+o2Z4A44Ej2+thFVRLG/eA7qprx88XXhnV5Bl8LHXTURpzB3Q==} + engines: {node: '>=20.18.1'} + vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1333,6 +1340,8 @@ snapshots: undici-types@6.21.0: {} + undici@7.24.2: {} + vite-node@3.2.4(@types/node@22.19.15): dependencies: cac: 6.7.14