{"version":3,"file":"wechat.mjs","names":[],"sources":["../../src/social-providers/wechat.ts"],"sourcesContent":["import { betterFetch } from \"@better-fetch/fetch\";\nimport type { OAuth2Tokens, OAuthProvider, ProviderOptions } from \"../oauth2\";\n\n/**\n * WeChat user profile information\n * @see https://developers.weixin.qq.com/doc/oplatform/en/Website_App/WeChat_Login/Wechat_Login.html\n */\nexport interface WeChatProfile extends Record<string, any> {\n\t/**\n\t * User's unique OpenID\n\t */\n\topenid: string;\n\t/**\n\t * User's nickname\n\t */\n\tnickname: string;\n\t/**\n\t * User's avatar image URL\n\t */\n\theadimgurl: string;\n\t/**\n\t * User's privileges\n\t */\n\tprivilege: string[];\n\t/**\n\t * User's UnionID (unique across the developer's various applications)\n\t */\n\tunionid?: string;\n\t/** @note Email is currently unsupported by WeChat */\n\temail?: string;\n}\n\nexport interface WeChatOptions extends ProviderOptions<WeChatProfile> {\n\t/**\n\t * WeChat App ID\n\t */\n\tclientId: string;\n\t/**\n\t * WeChat App Secret\n\t */\n\tclientSecret: string;\n\t/**\n\t * Platform type for WeChat login\n\t * - Currently only supports \"WebsiteApp\" for WeChat Website Application (网站应用)\n\t * @default \"WebsiteApp\"\n\t */\n\tplatformType?: \"WebsiteApp\";\n\n\t/**\n\t * UI language for the WeChat login page\n\t * cn for Simplified Chinese, en for English\n\t * @default \"cn\" if left undefined\n\t */\n\tlang?: \"cn\" | \"en\";\n}\n\nexport const wechat = (options: WeChatOptions) => {\n\treturn {\n\t\tid: \"wechat\",\n\t\tname: \"WeChat\",\n\t\tcreateAuthorizationURL({ state, scopes, redirectURI }) {\n\t\t\tconst _scopes = options.disableDefaultScope ? [] : [\"snsapi_login\"];\n\t\t\toptions.scope && _scopes.push(...options.scope);\n\t\t\tscopes && _scopes.push(...scopes);\n\n\t\t\t// WeChat uses non-standard OAuth2 parameters (appid instead of client_id)\n\t\t\t// and requires a fragment (#wechat_redirect), so we construct the URL manually.\n\t\t\tconst url = new URL(\"https://open.weixin.qq.com/connect/qrconnect\");\n\t\t\turl.searchParams.set(\"scope\", _scopes.join(\",\"));\n\t\t\turl.searchParams.set(\"response_type\", \"code\");\n\t\t\turl.searchParams.set(\"appid\", options.clientId);\n\t\t\turl.searchParams.set(\"redirect_uri\", options.redirectURI || redirectURI);\n\t\t\turl.searchParams.set(\"state\", state);\n\t\t\turl.searchParams.set(\"lang\", options.lang || \"cn\");\n\t\t\turl.hash = \"wechat_redirect\";\n\n\t\t\treturn url;\n\t\t},\n\n\t\t// WeChat uses non-standard token exchange (appid/secret instead of\n\t\t// client_id/client_secret, GET instead of POST), so shared helpers\n\t\t// like validateAuthorizationCode/getOAuth2Tokens cannot be used directly.\n\t\tvalidateAuthorizationCode: async ({ code }) => {\n\t\t\tconst params = new URLSearchParams({\n\t\t\t\tappid: options.clientId,\n\t\t\t\tsecret: options.clientSecret,\n\t\t\t\tcode: code,\n\t\t\t\tgrant_type: \"authorization_code\",\n\t\t\t});\n\n\t\t\tconst { data: tokenData, error } = await betterFetch<{\n\t\t\t\taccess_token: string;\n\t\t\t\texpires_in: number;\n\t\t\t\trefresh_token: string;\n\t\t\t\topenid: string;\n\t\t\t\tscope: string;\n\t\t\t\tunionid?: string;\n\t\t\t\terrcode?: number;\n\t\t\t\terrmsg?: string;\n\t\t\t}>(\n\t\t\t\t\"https://api.weixin.qq.com/sns/oauth2/access_token?\" +\n\t\t\t\t\tparams.toString(),\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tif (error || !tokenData || tokenData.errcode) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to validate authorization code: ${tokenData?.errmsg || error?.message || \"Unknown error\"}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttokenType: \"Bearer\" as const,\n\t\t\t\taccessToken: tokenData.access_token,\n\t\t\t\trefreshToken: tokenData.refresh_token,\n\t\t\t\taccessTokenExpiresAt: new Date(\n\t\t\t\t\tDate.now() + tokenData.expires_in * 1000,\n\t\t\t\t),\n\t\t\t\tscopes: tokenData.scope.split(\",\"),\n\t\t\t\t// WeChat requires openid for the userinfo endpoint, which is\n\t\t\t\t// returned alongside the access token.\n\t\t\t\topenid: tokenData.openid,\n\t\t\t\tunionid: tokenData.unionid,\n\t\t\t};\n\t\t},\n\n\t\trefreshAccessToken: options.refreshAccessToken\n\t\t\t? options.refreshAccessToken\n\t\t\t: async (refreshToken) => {\n\t\t\t\t\tconst params = new URLSearchParams({\n\t\t\t\t\t\tappid: options.clientId,\n\t\t\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\t\t\trefresh_token: refreshToken,\n\t\t\t\t\t});\n\n\t\t\t\t\tconst { data: tokenData, error } = await betterFetch<{\n\t\t\t\t\t\taccess_token: string;\n\t\t\t\t\t\texpires_in: number;\n\t\t\t\t\t\trefresh_token: string;\n\t\t\t\t\t\topenid: string;\n\t\t\t\t\t\tscope: string;\n\t\t\t\t\t\terrcode?: number;\n\t\t\t\t\t\terrmsg?: string;\n\t\t\t\t\t}>(\n\t\t\t\t\t\t\"https://api.weixin.qq.com/sns/oauth2/refresh_token?\" +\n\t\t\t\t\t\t\tparams.toString(),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\n\t\t\t\t\tif (error || !tokenData || tokenData.errcode) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`Failed to refresh access token: ${tokenData?.errmsg || error?.message || \"Unknown error\"}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttokenType: \"Bearer\" as const,\n\t\t\t\t\t\taccessToken: tokenData.access_token,\n\t\t\t\t\t\trefreshToken: tokenData.refresh_token,\n\t\t\t\t\t\taccessTokenExpiresAt: new Date(\n\t\t\t\t\t\t\tDate.now() + tokenData.expires_in * 1000,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tscopes: tokenData.scope.split(\",\"),\n\t\t\t\t\t};\n\t\t\t\t},\n\n\t\tasync getUserInfo(token) {\n\t\t\tif (options.getUserInfo) {\n\t\t\t\treturn options.getUserInfo(token);\n\t\t\t}\n\n\t\t\tconst openid = (token as OAuth2Tokens & { openid?: string }).openid;\n\n\t\t\tif (!openid) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst params = new URLSearchParams({\n\t\t\t\taccess_token: token.accessToken || \"\",\n\t\t\t\topenid: openid,\n\t\t\t\tlang: \"zh_CN\",\n\t\t\t});\n\n\t\t\tconst { data: profile, error } = await betterFetch<\n\t\t\t\tWeChatProfile & { errcode?: number; errmsg?: string }\n\t\t\t>(\"https://api.weixin.qq.com/sns/userinfo?\" + params.toString(), {\n\t\t\t\tmethod: \"GET\",\n\t\t\t});\n\n\t\t\tif (error || !profile || profile.errcode) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst userMap = await options.mapProfileToUser?.(profile);\n\t\t\treturn {\n\t\t\t\tuser: {\n\t\t\t\t\tid: profile.unionid || profile.openid || openid,\n\t\t\t\t\tname: profile.nickname,\n\t\t\t\t\temail: profile.email || null,\n\t\t\t\t\timage: profile.headimgurl,\n\t\t\t\t\temailVerified: false,\n\t\t\t\t\t...userMap,\n\t\t\t\t},\n\t\t\t\tdata: profile,\n\t\t\t};\n\t\t},\n\t\toptions,\n\t} satisfies OAuthProvider<WeChatProfile, WeChatOptions>;\n};\n"],"mappings":";;;AAwDA,MAAa,UAAU,YAA2B;AACjD,QAAO;EACN,IAAI;EACJ,MAAM;EACN,uBAAuB,EAAE,OAAO,QAAQ,eAAe;GACtD,MAAM,UAAU,QAAQ,sBAAsB,EAAE,GAAG,CAAC,eAAe;AACnE,WAAQ,SAAS,QAAQ,KAAK,GAAG,QAAQ,MAAM;AAC/C,aAAU,QAAQ,KAAK,GAAG,OAAO;GAIjC,MAAM,MAAM,IAAI,IAAI,+CAA+C;AACnE,OAAI,aAAa,IAAI,SAAS,QAAQ,KAAK,IAAI,CAAC;AAChD,OAAI,aAAa,IAAI,iBAAiB,OAAO;AAC7C,OAAI,aAAa,IAAI,SAAS,QAAQ,SAAS;AAC/C,OAAI,aAAa,IAAI,gBAAgB,QAAQ,eAAe,YAAY;AACxE,OAAI,aAAa,IAAI,SAAS,MAAM;AACpC,OAAI,aAAa,IAAI,QAAQ,QAAQ,QAAQ,KAAK;AAClD,OAAI,OAAO;AAEX,UAAO;;EAMR,2BAA2B,OAAO,EAAE,WAAW;GAQ9C,MAAM,EAAE,MAAM,WAAW,UAAU,MAAM,YAUxC,uDAjBc,IAAI,gBAAgB;IAClC,OAAO,QAAQ;IACf,QAAQ,QAAQ;IACV;IACN,YAAY;IACZ,CAAC,CAaO,UAAU,EAClB,EACC,QAAQ,OACR,CACD;AAED,OAAI,SAAS,CAAC,aAAa,UAAU,QACpC,OAAM,IAAI,MACT,0CAA0C,WAAW,UAAU,OAAO,WAAW,kBACjF;AAGF,UAAO;IACN,WAAW;IACX,aAAa,UAAU;IACvB,cAAc,UAAU;IACxB,sBAAsB,IAAI,KACzB,KAAK,KAAK,GAAG,UAAU,aAAa,IACpC;IACD,QAAQ,UAAU,MAAM,MAAM,IAAI;IAGlC,QAAQ,UAAU;IAClB,SAAS,UAAU;IACnB;;EAGF,oBAAoB,QAAQ,qBACzB,QAAQ,qBACR,OAAO,iBAAiB;GAOxB,MAAM,EAAE,MAAM,WAAW,UAAU,MAAM,YASxC,wDAfc,IAAI,gBAAgB;IAClC,OAAO,QAAQ;IACf,YAAY;IACZ,eAAe;IACf,CAAC,CAYO,UAAU,EAClB,EACC,QAAQ,OACR,CACD;AAED,OAAI,SAAS,CAAC,aAAa,UAAU,QACpC,OAAM,IAAI,MACT,mCAAmC,WAAW,UAAU,OAAO,WAAW,kBAC1E;AAGF,UAAO;IACN,WAAW;IACX,aAAa,UAAU;IACvB,cAAc,UAAU;IACxB,sBAAsB,IAAI,KACzB,KAAK,KAAK,GAAG,UAAU,aAAa,IACpC;IACD,QAAQ,UAAU,MAAM,MAAM,IAAI;IAClC;;EAGJ,MAAM,YAAY,OAAO;AACxB,OAAI,QAAQ,YACX,QAAO,QAAQ,YAAY,MAAM;GAGlC,MAAM,SAAU,MAA6C;AAE7D,OAAI,CAAC,OACJ,QAAO;GASR,MAAM,EAAE,MAAM,SAAS,UAAU,MAAM,YAErC,4CARa,IAAI,gBAAgB;IAClC,cAAc,MAAM,eAAe;IAC3B;IACR,MAAM;IACN,CAAC,CAImD,UAAU,EAAE,EAChE,QAAQ,OACR,CAAC;AAEF,OAAI,SAAS,CAAC,WAAW,QAAQ,QAChC,QAAO;GAGR,MAAM,UAAU,MAAM,QAAQ,mBAAmB,QAAQ;AACzD,UAAO;IACN,MAAM;KACL,IAAI,QAAQ,WAAW,QAAQ,UAAU;KACzC,MAAM,QAAQ;KACd,OAAO,QAAQ,SAAS;KACxB,OAAO,QAAQ;KACf,eAAe;KACf,GAAG;KACH;IACD,MAAM;IACN;;EAEF;EACA"}