const base = () => (process.env.TELEGRAM_GATEWAY_URL || 'http://host.docker.internal:3000/api').replace(/\/$/, '') let gatewayToken = process.env.TELEGRAM_GATEWAY_TOKEN || '' let refreshPromise function tokenExpiresSoon(token) { try { const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString('utf8')) return !payload.exp || payload.exp * 1000 < Date.now() + 5 * 60 * 1000 } catch { return true } } async function refreshGatewayToken() { if (refreshPromise) return refreshPromise refreshPromise = (async () => { const email = process.env.TELEGRAM_GATEWAY_SERVICE_EMAIL const password = process.env.TELEGRAM_GATEWAY_SERVICE_PASSWORD const tenantId = process.env.TELEGRAM_GATEWAY_TENANT_ID if (!email || !password || !tenantId) { throw Object.assign(new Error('Telegram 网关服务账号凭据尚未配置'), { status: 503 }) } const response = await fetch(`${base()}/auth/login`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ email, password, tenantId }), }) const raw = await response.text() let result try { result = raw ? JSON.parse(raw) : null } catch { result = raw } const token = result?.data?.token || result?.token if (!response.ok || !token) { throw Object.assign(new Error(result?.message || 'Telegram 网关服务账号续签失败'), { status: response.status || 503 }) } gatewayToken = token return token })().finally(() => { refreshPromise = undefined }) return refreshPromise } export async function gatewayRequest(path, options = {}) { const tenantId = process.env.TELEGRAM_GATEWAY_TENANT_ID if (!tenantId) throw Object.assign(new Error('Telegram 网关租户尚未配置'), { status: 503 }) if (!gatewayToken || tokenExpiresSoon(gatewayToken)) await refreshGatewayToken() const send = () => fetch(`${base()}${path}`, { ...options, headers: { ...(options.body instanceof FormData ? {} : { 'content-type': 'application/json' }), authorization: `Bearer ${gatewayToken}`, 'x-tenant-id': tenantId, ...(options.headers || {}), }, }) let response = await send() if (response.status === 401) { await refreshGatewayToken() response = await send() } const raw = await response.text() let result try { result = raw ? JSON.parse(raw) : null } catch { result = raw } if (!response.ok) { throw Object.assign(new Error(result?.message || `Telegram 网关请求失败 (${response.status})`), { status: response.status }) } return result?.data ?? result } export function postGateway(path, body) { return gatewayRequest(path, { method: 'POST', body: JSON.stringify(body) }) } export function putGateway(path, body) { return gatewayRequest(path, { method: 'PUT', body: JSON.stringify(body) }) } export function uploadGateway(path, formData) { return gatewayRequest(path, { method: 'POST', body: formData }) }