import { fetch } from 'undici'; const JSCODE2SESSION_URL = 'https://api.weixin.qq.com/sns/jscode2session'; export function loadWechatMiniappConfig(env = process.env) { const appId = env.H5_WECHAT_MINIAPP_APP_ID?.trim() ?? env.H5_WECHAT_APP_ID?.trim() ?? ''; const appSecret = env.H5_WECHAT_MINIAPP_APP_SECRET?.trim() ?? env.H5_WECHAT_APP_SECRET?.trim() ?? ''; return { enabled: Boolean(appId && appSecret), appId, appSecret, }; } export async function exchangeMiniProgramCode( { appId, appSecret, code, fetchImpl = fetch } = {}, ) { const jsCode = String(code ?? '').trim(); if (!appId || !appSecret) { throw Object.assign(new Error('小程序登录未配置 AppID/AppSecret'), { code: 'wechat_miniapp_not_configured', }); } if (!jsCode) { throw Object.assign(new Error('缺少微信登录 code'), { code: 'invalid_code' }); } const url = new URL(JSCODE2SESSION_URL); url.searchParams.set('appid', appId); url.searchParams.set('secret', appSecret); url.searchParams.set('js_code', jsCode); url.searchParams.set('grant_type', 'authorization_code'); const response = await fetchImpl(url); const payload = await response.json().catch(() => ({})); if (!response.ok) { throw Object.assign(new Error('微信登录服务暂不可用'), { code: 'wechat_miniapp_http_failed', status: response.status, }); } if (payload.errcode) { throw Object.assign(new Error(payload.errmsg || '微信 code 无效或已过期'), { code: 'wechat_miniapp_code_failed', errcode: payload.errcode, }); } const openid = String(payload.openid ?? '').trim(); if (!openid) { throw Object.assign(new Error('微信未返回 openid'), { code: 'wechat_miniapp_openid_missing' }); } return { openid, sessionKey: payload.session_key ?? null, unionid: payload.unionid ? String(payload.unionid).trim() : null, }; }