@sohu-bpd/wechat
Advanced tools
+10
-5
@@ -18,4 +18,9 @@ /** | ||
| interface GlobalConfig { | ||
| /** 获取签名参数的函数,接收当前页面 URL,返回签名参数 */ | ||
| getSignature: (url: string) => Promise<SignatureResult>; | ||
| /** | ||
| * 获取签名参数的函数,接收当前页面 URL,返回签名参数 | ||
| * - 在 https://act.go.sohu.com 或 https://test.r.ads.sohu.com 域名下,此参数可选 | ||
| * - 未提供时将自动使用内置签名获取函数(请求 /wechat/ticket) | ||
| * - 在其他域名下,此参数必填 | ||
| */ | ||
| getSignature?: (url: string) => Promise<SignatureResult>; | ||
| /** 是否开启调试模式,默认 false */ | ||
@@ -34,8 +39,8 @@ debug?: boolean; | ||
| */ | ||
| declare function config(options: GlobalConfig): void; | ||
| declare function config(options?: GlobalConfig): void; | ||
| /** | ||
| * 获取全局配置 | ||
| * @returns 全局配置,如果未配置则抛出错误 | ||
| * @returns 全局配置,如果未配置则尝试自动初始化(仅在支持的域名下) | ||
| */ | ||
| declare function getConfig(): GlobalConfig; | ||
| declare function getConfig(): Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig; | ||
| /** | ||
@@ -42,0 +47,0 @@ * 检查是否已配置 |
+10
-5
@@ -18,4 +18,9 @@ /** | ||
| interface GlobalConfig { | ||
| /** 获取签名参数的函数,接收当前页面 URL,返回签名参数 */ | ||
| getSignature: (url: string) => Promise<SignatureResult>; | ||
| /** | ||
| * 获取签名参数的函数,接收当前页面 URL,返回签名参数 | ||
| * - 在 https://act.go.sohu.com 或 https://test.r.ads.sohu.com 域名下,此参数可选 | ||
| * - 未提供时将自动使用内置签名获取函数(请求 /wechat/ticket) | ||
| * - 在其他域名下,此参数必填 | ||
| */ | ||
| getSignature?: (url: string) => Promise<SignatureResult>; | ||
| /** 是否开启调试模式,默认 false */ | ||
@@ -34,8 +39,8 @@ debug?: boolean; | ||
| */ | ||
| declare function config(options: GlobalConfig): void; | ||
| declare function config(options?: GlobalConfig): void; | ||
| /** | ||
| * 获取全局配置 | ||
| * @returns 全局配置,如果未配置则抛出错误 | ||
| * @returns 全局配置,如果未配置则尝试自动初始化(仅在支持的域名下) | ||
| */ | ||
| declare function getConfig(): GlobalConfig; | ||
| declare function getConfig(): Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig; | ||
| /** | ||
@@ -42,0 +47,0 @@ * 检查是否已配置 |
+74
-2
@@ -5,4 +5,70 @@ var SohuWechat = (function (exports) { | ||
| // src/config.ts | ||
| var BUILT_IN_SIGNATURE_DOMAINS = [ | ||
| "https://act.go.sohu.com", | ||
| "https://test.r.ads.sohu.com" | ||
| ]; | ||
| function isBuiltInSignatureDomain() { | ||
| if (typeof window === "undefined") return false; | ||
| const origin = window.location.origin; | ||
| return BUILT_IN_SIGNATURE_DOMAINS.includes(origin); | ||
| } | ||
| async function httpGet(url) { | ||
| if (typeof fetch !== "undefined") { | ||
| const response = await fetch(url); | ||
| if (!response.ok) { | ||
| throw new Error(`Failed to fetch signature: ${response.status} ${response.statusText}`); | ||
| } | ||
| return await response.json(); | ||
| } | ||
| return new Promise((resolve, reject) => { | ||
| const xhr = new XMLHttpRequest(); | ||
| xhr.open("GET", url, true); | ||
| xhr.onload = () => { | ||
| if (xhr.status >= 200 && xhr.status < 300) { | ||
| try { | ||
| const result = JSON.parse(xhr.responseText); | ||
| resolve(result); | ||
| } catch (error) { | ||
| reject(new Error(`Failed to parse response: ${error}`)); | ||
| } | ||
| } else { | ||
| reject(new Error(`Failed to fetch signature: ${xhr.status} ${xhr.statusText}`)); | ||
| } | ||
| }; | ||
| xhr.onerror = () => { | ||
| reject(new Error("Network error occurred")); | ||
| }; | ||
| xhr.send(); | ||
| }); | ||
| } | ||
| async function builtInGetSignature(url) { | ||
| const apiUrl = `/wechat/ticket?url=${encodeURIComponent(url)}`; | ||
| const result = await httpGet(apiUrl); | ||
| if (result.code !== 0) { | ||
| throw new Error(`Signature API error: ${result.message}`); | ||
| } | ||
| return { | ||
| appId: result.data.app_id, | ||
| timestamp: result.data.timestamp, | ||
| nonceStr: result.data.nonce_str, | ||
| signature: result.data.signature | ||
| }; | ||
| } | ||
| var globalConfig = null; | ||
| function config(options) { | ||
| function config(options = {}) { | ||
| if (!options.getSignature) { | ||
| if (isBuiltInSignatureDomain()) { | ||
| options.getSignature = builtInGetSignature; | ||
| if (options.debug === void 0) { | ||
| options.debug = false; | ||
| } | ||
| if (options.spa === void 0) { | ||
| options.spa = true; | ||
| } | ||
| } else { | ||
| throw new Error( | ||
| "\u5F53\u524D\u57DF\u540D\u4E0D\u652F\u6301\u5185\u7F6E\u7B7E\u540D\uFF0C\u8BF7\u63D0\u4F9B getSignature \u51FD\u6570\u3002\u5185\u7F6E\u7B7E\u540D\u4EC5\u5728\u4EE5\u4E0B\u57DF\u540D\u4E0B\u53EF\u7528\uFF1A" + BUILT_IN_SIGNATURE_DOMAINS.join(", ") | ||
| ); | ||
| } | ||
| } | ||
| globalConfig = options; | ||
@@ -12,3 +78,9 @@ } | ||
| if (!globalConfig) { | ||
| throw new Error("\u8BF7\u5148\u8C03\u7528 config() \u8FDB\u884C\u914D\u7F6E"); | ||
| if (isBuiltInSignatureDomain()) { | ||
| config({}); | ||
| } else { | ||
| throw new Error( | ||
| "\u8BF7\u5148\u8C03\u7528 config() \u8FDB\u884C\u914D\u7F6E\u3002\u5728 " + BUILT_IN_SIGNATURE_DOMAINS.join(", ") + " \u57DF\u540D\u4E0B\u53EF\u4EE5\u81EA\u52A8\u4F7F\u7528\u5185\u7F6E\u914D\u7F6E\u3002" | ||
| ); | ||
| } | ||
| } | ||
@@ -15,0 +87,0 @@ return globalConfig; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/config.ts","../src/sdk.ts","../src/share.ts","../src/init.ts"],"names":["config"],"mappings":"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","file":"index.global.js","sourcesContent":["/**\n * 微信 JS-SDK 签名参数\n */\nexport interface SignatureResult {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n}\n\n/**\n * 全局配置选项\n */\nexport interface GlobalConfig {\n /** 获取签名参数的函数,接收当前页面 URL,返回签名参数 */\n getSignature: (url: string) => Promise<SignatureResult>\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /**\n * 是否为 SPA 单页应用模式,默认 true\n * - true: 每次调用 API 时检测 URL 变化,变化则重新初始化\n * - false: 仅初始化一次\n */\n spa?: boolean\n}\n\nlet globalConfig: GlobalConfig | null = null\n\n/**\n * 设置全局配置\n * @param options - 配置选项\n */\nexport function config(options: GlobalConfig): void {\n globalConfig = options\n}\n\n/**\n * 获取全局配置\n * @returns 全局配置,如果未配置则抛出错误\n */\nexport function getConfig(): GlobalConfig {\n if (!globalConfig) {\n throw new Error('请先调用 config() 进行配置')\n }\n return globalConfig\n}\n\n/**\n * 检查是否已配置\n */\nexport function isConfigured(): boolean {\n return globalConfig !== null\n}\n","import { getConfig } from './config'\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n updateAppMessageShareData: (options: {\n title: string\n desc: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n updateTimelineShareData: (options: {\n title: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n}\n\nlet sdkInitPromise: Promise<void> | null = null\nlet currentInitUrl: string | null = null\nlet entryUrl: string | null = null // iOS 微信需要用首次进入的 URL\n\n/**\n * 检测是否为 iOS 微信浏览器\n */\nfunction isIOSWechat(): boolean {\n if (typeof navigator === 'undefined') return false\n const ua = navigator.userAgent.toLowerCase()\n return /iphone|ipad|ipod/.test(ua) && /micromessenger/.test(ua)\n}\n\n/**\n * 获取用于签名的 URL\n * iOS 微信需要用首次进入页面的 URL,Android 用当前 URL\n */\nfunction getSignatureUrl(): string {\n if (typeof window === 'undefined') return ''\n\n const currentUrl = window.location.href.split('#')[0]\n\n if (isIOSWechat()) {\n // iOS 微信:用首次进入的 URL\n if (!entryUrl) {\n entryUrl = currentUrl\n }\n return entryUrl\n }\n\n // Android 或其他:用当前 URL\n return currentUrl\n}\n\n/**\n * 获取 wx 对象\n */\nexport function getWx(): WxSDK {\n if (typeof window === 'undefined') {\n throw new Error('window is not defined')\n }\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n throw new Error('wx is not defined')\n }\n return wx\n}\n\n/**\n * 初始化 SDK(获取签名并调用 wx.config)\n * SPA 模式下,URL 变化时会重新初始化(Android)\n * iOS 微信始终使用首次进入的 URL 进行签名\n * 注意:需要使用者在全局引入微信 JS-SDK,确保 window.wx 可用\n */\nexport async function initSDK(jsApiList: string[]): Promise<void> {\n const cfg = getConfig()\n const signatureUrl = getSignatureUrl()\n const isSpa = cfg.spa !== false // 默认为 true\n\n // 非 SPA 模式或 URL 没有变化,且已经初始化过,直接返回\n if (sdkInitPromise && (!isSpa || currentInitUrl === signatureUrl)) {\n return sdkInitPromise\n }\n\n // URL 变化或首次初始化\n currentInitUrl = signatureUrl\n\n sdkInitPromise = (async () => {\n // 获取签名\n const signatureResult = await cfg.getSignature(signatureUrl)\n\n // 调用 wx.config\n const wx = getWx()\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: cfg.debug ?? false,\n appId: signatureResult.appId,\n timestamp: signatureResult.timestamp,\n nonceStr: signatureResult.nonceStr,\n signature: signatureResult.signature,\n jsApiList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n // 初始化失败,清除缓存以便下次重试\n sdkInitPromise = null\n currentInitUrl = null\n reject(new Error(`wx.config failed: ${res.errMsg}`))\n })\n })\n })()\n\n return sdkInitPromise\n}\n\n/**\n * 重置 SDK 状态(用于测试或强制重新初始化)\n */\nexport function resetSDK(): void {\n sdkInitPromise = null\n currentInitUrl = null\n entryUrl = null\n}\n","import { initSDK, getWx } from './sdk'\n\n/**\n * 分享参数\n */\nexport interface ShareOptions {\n /** 分享标题 */\n title: string\n /** 分享描述(分享给朋友时显示) */\n desc?: string\n /** 分享链接,默认为当前页面 URL */\n link?: string\n /** 分享图标 URL */\n imgUrl: string\n}\n\nconst SHARE_JS_API_LIST = [\n 'updateAppMessageShareData',\n 'updateTimelineShareData',\n]\n\n/**\n * 设置微信分享内容\n * 会自动加载 SDK 并初始化,然后设置分享内容\n * @param options - 分享参数\n */\nexport async function share(options: ShareOptions): Promise<void> {\n // 确保 SDK 已初始化\n await initSDK(SHARE_JS_API_LIST)\n\n const wx = getWx()\n const link = options.link ?? (typeof window !== 'undefined' ? window.location.href : '')\n\n // 设置分享给朋友\n await new Promise<void>((resolve, reject) => {\n wx.updateAppMessageShareData({\n title: options.title,\n desc: options.desc ?? '',\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateAppMessageShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n\n // 设置分享到朋友圈\n await new Promise<void>((resolve, reject) => {\n wx.updateTimelineShareData({\n title: options.title,\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateTimelineShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n}\n","/**\n * 微信 JS-SDK wx.config 所需的配置参数\n */\nexport interface Config {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n /** 需要使用的 JS 接口列表 */\n jsApiList: string[]\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /** 需要使用的开放标签列表 */\n openTagList?: string[]\n}\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n}\n\n/**\n * 初始化微信 JS-SDK,调用 wx.config 并返回 Promise\n * 注意:使用此函数前,需要在 HTML 中提前引入微信 JS-SDK 脚本,确保 window.wx 可用\n * @param config - 微信 JS-SDK 配置参数\n * @returns Promise,ready 时 resolve,error 时 reject 并携带错误信息\n */\nexport function init(config: Config): Promise<void> {\n if (typeof window === 'undefined') {\n return Promise.reject(new Error('init: window is not defined'))\n }\n\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n return Promise.reject(new Error('init: wx is not defined, please load WeChat JS-SDK first'))\n }\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: config.debug ?? false,\n appId: config.appId,\n timestamp: config.timestamp,\n nonceStr: config.nonceStr,\n signature: config.signature,\n jsApiList: config.jsApiList,\n openTagList: config.openTagList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n reject(new Error(`init: ${res.errMsg}`))\n })\n })\n}\n"]} | ||
| {"version":3,"sources":["../src/config.ts","../src/sdk.ts","../src/share.ts","../src/init.ts"],"names":["config"],"mappings":"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","file":"index.global.js","sourcesContent":["/**\n * 微信 JS-SDK 签名参数\n */\nexport interface SignatureResult {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n}\n\n/**\n * 内置签名接口返回值\n */\ninterface BuiltInSignatureResponse {\n code: number\n data: {\n app_id: string\n timestamp: number\n nonce_str: string\n signature: string\n }\n message: string\n}\n\n/**\n * 支持内置签名的域名列表\n */\nconst BUILT_IN_SIGNATURE_DOMAINS = [\n 'https://act.go.sohu.com',\n 'https://test.r.ads.sohu.com',\n]\n\n/**\n * 检查当前域名是否支持内置签名\n */\nfunction isBuiltInSignatureDomain(): boolean {\n if (typeof window === 'undefined') return false\n const origin = window.location.origin\n return BUILT_IN_SIGNATURE_DOMAINS.includes(origin)\n}\n\n/**\n * 发起 HTTP GET 请求,支持 fetch 和 XMLHttpRequest 回退\n */\nasync function httpGet(url: string): Promise<BuiltInSignatureResponse> {\n // 优先使用 fetch API\n if (typeof fetch !== 'undefined') {\n const response = await fetch(url)\n\n if (!response.ok) {\n throw new Error(`Failed to fetch signature: ${response.status} ${response.statusText}`)\n }\n\n return await response.json()\n }\n\n // 回退到 XMLHttpRequest\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest()\n xhr.open('GET', url, true)\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const result = JSON.parse(xhr.responseText)\n resolve(result)\n } catch (error) {\n reject(new Error(`Failed to parse response: ${error}`))\n }\n } else {\n reject(new Error(`Failed to fetch signature: ${xhr.status} ${xhr.statusText}`))\n }\n }\n\n xhr.onerror = () => {\n reject(new Error('Network error occurred'))\n }\n\n xhr.send()\n })\n}\n\n/**\n * 内置的签名获取函数(仅在特定域名下可用)\n */\nasync function builtInGetSignature(url: string): Promise<SignatureResult> {\n const apiUrl = `/wechat/ticket?url=${encodeURIComponent(url)}`\n const result = await httpGet(apiUrl)\n\n if (result.code !== 0) {\n throw new Error(`Signature API error: ${result.message}`)\n }\n\n return {\n appId: result.data.app_id,\n timestamp: result.data.timestamp,\n nonceStr: result.data.nonce_str,\n signature: result.data.signature,\n }\n}\n\n/**\n * 全局配置选项\n */\nexport interface GlobalConfig {\n /**\n * 获取签名参数的函数,接收当前页面 URL,返回签名参数\n * - 在 https://act.go.sohu.com 或 https://test.r.ads.sohu.com 域名下,此参数可选\n * - 未提供时将自动使用内置签名获取函数(请求 /wechat/ticket)\n * - 在其他域名下,此参数必填\n */\n getSignature?: (url: string) => Promise<SignatureResult>\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /**\n * 是否为 SPA 单页应用模式,默认 true\n * - true: 每次调用 API 时检测 URL 变化,变化则重新初始化\n * - false: 仅初始化一次\n */\n spa?: boolean\n}\n\nlet globalConfig: GlobalConfig | null = null\n\n/**\n * 设置全局配置\n * @param options - 配置选项\n */\nexport function config(options: GlobalConfig = {}): void {\n // 如果未提供 getSignature,尝试使用内置签名函数\n if (!options.getSignature) {\n if (isBuiltInSignatureDomain()) {\n options.getSignature = builtInGetSignature\n // 设置默认值,确保未初始化时也有合理的默认配置\n if (options.debug === undefined) {\n options.debug = false\n }\n if (options.spa === undefined) {\n options.spa = true\n }\n } else {\n throw new Error(\n '当前域名不支持内置签名,请提供 getSignature 函数。' +\n '内置签名仅在以下域名下可用:' +\n BUILT_IN_SIGNATURE_DOMAINS.join(', ')\n )\n }\n }\n\n globalConfig = options as Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig\n}\n\n/**\n * 获取全局配置\n * @returns 全局配置,如果未配置则尝试自动初始化(仅在支持的域名下)\n */\nexport function getConfig(): Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig {\n if (!globalConfig) {\n // 在支持的域名下,自动初始化默认配置\n if (isBuiltInSignatureDomain()) {\n config({})\n } else {\n throw new Error(\n '请先调用 config() 进行配置。' +\n '在 ' +\n BUILT_IN_SIGNATURE_DOMAINS.join(', ') +\n ' 域名下可以自动使用内置配置。'\n )\n }\n }\n return globalConfig as Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig\n}\n\n/**\n * 检查是否已配置\n */\nexport function isConfigured(): boolean {\n return globalConfig !== null\n}\n\n/**\n * 重置配置(仅用于测试)\n * @internal\n */\nexport function resetConfig(): void {\n globalConfig = null\n}\n","import { getConfig } from './config'\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n updateAppMessageShareData: (options: {\n title: string\n desc: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n updateTimelineShareData: (options: {\n title: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n}\n\nlet sdkInitPromise: Promise<void> | null = null\nlet currentInitUrl: string | null = null\nlet entryUrl: string | null = null // iOS 微信需要用首次进入的 URL\n\n/**\n * 检测是否为 iOS 微信浏览器\n */\nfunction isIOSWechat(): boolean {\n if (typeof navigator === 'undefined') return false\n const ua = navigator.userAgent.toLowerCase()\n return /iphone|ipad|ipod/.test(ua) && /micromessenger/.test(ua)\n}\n\n/**\n * 获取用于签名的 URL\n * iOS 微信需要用首次进入页面的 URL,Android 用当前 URL\n */\nfunction getSignatureUrl(): string {\n if (typeof window === 'undefined') return ''\n\n const currentUrl = window.location.href.split('#')[0]\n\n if (isIOSWechat()) {\n // iOS 微信:用首次进入的 URL\n if (!entryUrl) {\n entryUrl = currentUrl\n }\n return entryUrl\n }\n\n // Android 或其他:用当前 URL\n return currentUrl\n}\n\n/**\n * 获取 wx 对象\n */\nexport function getWx(): WxSDK {\n if (typeof window === 'undefined') {\n throw new Error('window is not defined')\n }\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n throw new Error('wx is not defined')\n }\n return wx\n}\n\n/**\n * 初始化 SDK(获取签名并调用 wx.config)\n * SPA 模式下,URL 变化时会重新初始化(Android)\n * iOS 微信始终使用首次进入的 URL 进行签名\n * 注意:需要使用者在全局引入微信 JS-SDK,确保 window.wx 可用\n */\nexport async function initSDK(jsApiList: string[]): Promise<void> {\n const cfg = getConfig()\n const signatureUrl = getSignatureUrl()\n const isSpa = cfg.spa !== false // 默认为 true\n\n // 非 SPA 模式或 URL 没有变化,且已经初始化过,直接返回\n if (sdkInitPromise && (!isSpa || currentInitUrl === signatureUrl)) {\n return sdkInitPromise\n }\n\n // URL 变化或首次初始化\n currentInitUrl = signatureUrl\n\n sdkInitPromise = (async () => {\n // 获取签名\n const signatureResult = await cfg.getSignature(signatureUrl)\n\n // 调用 wx.config\n const wx = getWx()\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: cfg.debug ?? false,\n appId: signatureResult.appId,\n timestamp: signatureResult.timestamp,\n nonceStr: signatureResult.nonceStr,\n signature: signatureResult.signature,\n jsApiList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n // 初始化失败,清除缓存以便下次重试\n sdkInitPromise = null\n currentInitUrl = null\n reject(new Error(`wx.config failed: ${res.errMsg}`))\n })\n })\n })()\n\n return sdkInitPromise\n}\n\n/**\n * 重置 SDK 状态(用于测试或强制重新初始化)\n */\nexport function resetSDK(): void {\n sdkInitPromise = null\n currentInitUrl = null\n entryUrl = null\n}\n","import { initSDK, getWx } from './sdk'\n\n/**\n * 分享参数\n */\nexport interface ShareOptions {\n /** 分享标题 */\n title: string\n /** 分享描述(分享给朋友时显示) */\n desc?: string\n /** 分享链接,默认为当前页面 URL */\n link?: string\n /** 分享图标 URL */\n imgUrl: string\n}\n\nconst SHARE_JS_API_LIST = [\n 'updateAppMessageShareData',\n 'updateTimelineShareData',\n]\n\n/**\n * 设置微信分享内容\n * 会自动加载 SDK 并初始化,然后设置分享内容\n * @param options - 分享参数\n */\nexport async function share(options: ShareOptions): Promise<void> {\n // 确保 SDK 已初始化\n await initSDK(SHARE_JS_API_LIST)\n\n const wx = getWx()\n const link = options.link ?? (typeof window !== 'undefined' ? window.location.href : '')\n\n // 设置分享给朋友\n await new Promise<void>((resolve, reject) => {\n wx.updateAppMessageShareData({\n title: options.title,\n desc: options.desc ?? '',\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateAppMessageShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n\n // 设置分享到朋友圈\n await new Promise<void>((resolve, reject) => {\n wx.updateTimelineShareData({\n title: options.title,\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateTimelineShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n}\n","/**\n * 微信 JS-SDK wx.config 所需的配置参数\n */\nexport interface Config {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n /** 需要使用的 JS 接口列表 */\n jsApiList: string[]\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /** 需要使用的开放标签列表 */\n openTagList?: string[]\n}\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n}\n\n/**\n * 初始化微信 JS-SDK,调用 wx.config 并返回 Promise\n * 注意:使用此函数前,需要在 HTML 中提前引入微信 JS-SDK 脚本,确保 window.wx 可用\n * @param config - 微信 JS-SDK 配置参数\n * @returns Promise,ready 时 resolve,error 时 reject 并携带错误信息\n */\nexport function init(config: Config): Promise<void> {\n if (typeof window === 'undefined') {\n return Promise.reject(new Error('init: window is not defined'))\n }\n\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n return Promise.reject(new Error('init: wx is not defined, please load WeChat JS-SDK first'))\n }\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: config.debug ?? false,\n appId: config.appId,\n timestamp: config.timestamp,\n nonceStr: config.nonceStr,\n signature: config.signature,\n jsApiList: config.jsApiList,\n openTagList: config.openTagList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n reject(new Error(`init: ${res.errMsg}`))\n })\n })\n}\n"]} |
+74
-2
| 'use strict'; | ||
| // src/config.ts | ||
| var BUILT_IN_SIGNATURE_DOMAINS = [ | ||
| "https://act.go.sohu.com", | ||
| "https://test.r.ads.sohu.com" | ||
| ]; | ||
| function isBuiltInSignatureDomain() { | ||
| if (typeof window === "undefined") return false; | ||
| const origin = window.location.origin; | ||
| return BUILT_IN_SIGNATURE_DOMAINS.includes(origin); | ||
| } | ||
| async function httpGet(url) { | ||
| if (typeof fetch !== "undefined") { | ||
| const response = await fetch(url); | ||
| if (!response.ok) { | ||
| throw new Error(`Failed to fetch signature: ${response.status} ${response.statusText}`); | ||
| } | ||
| return await response.json(); | ||
| } | ||
| return new Promise((resolve, reject) => { | ||
| const xhr = new XMLHttpRequest(); | ||
| xhr.open("GET", url, true); | ||
| xhr.onload = () => { | ||
| if (xhr.status >= 200 && xhr.status < 300) { | ||
| try { | ||
| const result = JSON.parse(xhr.responseText); | ||
| resolve(result); | ||
| } catch (error) { | ||
| reject(new Error(`Failed to parse response: ${error}`)); | ||
| } | ||
| } else { | ||
| reject(new Error(`Failed to fetch signature: ${xhr.status} ${xhr.statusText}`)); | ||
| } | ||
| }; | ||
| xhr.onerror = () => { | ||
| reject(new Error("Network error occurred")); | ||
| }; | ||
| xhr.send(); | ||
| }); | ||
| } | ||
| async function builtInGetSignature(url) { | ||
| const apiUrl = `/wechat/ticket?url=${encodeURIComponent(url)}`; | ||
| const result = await httpGet(apiUrl); | ||
| if (result.code !== 0) { | ||
| throw new Error(`Signature API error: ${result.message}`); | ||
| } | ||
| return { | ||
| appId: result.data.app_id, | ||
| timestamp: result.data.timestamp, | ||
| nonceStr: result.data.nonce_str, | ||
| signature: result.data.signature | ||
| }; | ||
| } | ||
| var globalConfig = null; | ||
| function config(options) { | ||
| function config(options = {}) { | ||
| if (!options.getSignature) { | ||
| if (isBuiltInSignatureDomain()) { | ||
| options.getSignature = builtInGetSignature; | ||
| if (options.debug === void 0) { | ||
| options.debug = false; | ||
| } | ||
| if (options.spa === void 0) { | ||
| options.spa = true; | ||
| } | ||
| } else { | ||
| throw new Error( | ||
| "\u5F53\u524D\u57DF\u540D\u4E0D\u652F\u6301\u5185\u7F6E\u7B7E\u540D\uFF0C\u8BF7\u63D0\u4F9B getSignature \u51FD\u6570\u3002\u5185\u7F6E\u7B7E\u540D\u4EC5\u5728\u4EE5\u4E0B\u57DF\u540D\u4E0B\u53EF\u7528\uFF1A" + BUILT_IN_SIGNATURE_DOMAINS.join(", ") | ||
| ); | ||
| } | ||
| } | ||
| globalConfig = options; | ||
@@ -10,3 +76,9 @@ } | ||
| if (!globalConfig) { | ||
| throw new Error("\u8BF7\u5148\u8C03\u7528 config() \u8FDB\u884C\u914D\u7F6E"); | ||
| if (isBuiltInSignatureDomain()) { | ||
| config({}); | ||
| } else { | ||
| throw new Error( | ||
| "\u8BF7\u5148\u8C03\u7528 config() \u8FDB\u884C\u914D\u7F6E\u3002\u5728 " + BUILT_IN_SIGNATURE_DOMAINS.join(", ") + " \u57DF\u540D\u4E0B\u53EF\u4EE5\u81EA\u52A8\u4F7F\u7528\u5185\u7F6E\u914D\u7F6E\u3002" | ||
| ); | ||
| } | ||
| } | ||
@@ -13,0 +85,0 @@ return globalConfig; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/config.ts","../src/sdk.ts","../src/share.ts","../src/init.ts"],"names":["config"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 微信 JS-SDK 签名参数\n */\nexport interface SignatureResult {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n}\n\n/**\n * 全局配置选项\n */\nexport interface GlobalConfig {\n /** 获取签名参数的函数,接收当前页面 URL,返回签名参数 */\n getSignature: (url: string) => Promise<SignatureResult>\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /**\n * 是否为 SPA 单页应用模式,默认 true\n * - true: 每次调用 API 时检测 URL 变化,变化则重新初始化\n * - false: 仅初始化一次\n */\n spa?: boolean\n}\n\nlet globalConfig: GlobalConfig | null = null\n\n/**\n * 设置全局配置\n * @param options - 配置选项\n */\nexport function config(options: GlobalConfig): void {\n globalConfig = options\n}\n\n/**\n * 获取全局配置\n * @returns 全局配置,如果未配置则抛出错误\n */\nexport function getConfig(): GlobalConfig {\n if (!globalConfig) {\n throw new Error('请先调用 config() 进行配置')\n }\n return globalConfig\n}\n\n/**\n * 检查是否已配置\n */\nexport function isConfigured(): boolean {\n return globalConfig !== null\n}\n","import { getConfig } from './config'\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n updateAppMessageShareData: (options: {\n title: string\n desc: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n updateTimelineShareData: (options: {\n title: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n}\n\nlet sdkInitPromise: Promise<void> | null = null\nlet currentInitUrl: string | null = null\nlet entryUrl: string | null = null // iOS 微信需要用首次进入的 URL\n\n/**\n * 检测是否为 iOS 微信浏览器\n */\nfunction isIOSWechat(): boolean {\n if (typeof navigator === 'undefined') return false\n const ua = navigator.userAgent.toLowerCase()\n return /iphone|ipad|ipod/.test(ua) && /micromessenger/.test(ua)\n}\n\n/**\n * 获取用于签名的 URL\n * iOS 微信需要用首次进入页面的 URL,Android 用当前 URL\n */\nfunction getSignatureUrl(): string {\n if (typeof window === 'undefined') return ''\n\n const currentUrl = window.location.href.split('#')[0]\n\n if (isIOSWechat()) {\n // iOS 微信:用首次进入的 URL\n if (!entryUrl) {\n entryUrl = currentUrl\n }\n return entryUrl\n }\n\n // Android 或其他:用当前 URL\n return currentUrl\n}\n\n/**\n * 获取 wx 对象\n */\nexport function getWx(): WxSDK {\n if (typeof window === 'undefined') {\n throw new Error('window is not defined')\n }\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n throw new Error('wx is not defined')\n }\n return wx\n}\n\n/**\n * 初始化 SDK(获取签名并调用 wx.config)\n * SPA 模式下,URL 变化时会重新初始化(Android)\n * iOS 微信始终使用首次进入的 URL 进行签名\n * 注意:需要使用者在全局引入微信 JS-SDK,确保 window.wx 可用\n */\nexport async function initSDK(jsApiList: string[]): Promise<void> {\n const cfg = getConfig()\n const signatureUrl = getSignatureUrl()\n const isSpa = cfg.spa !== false // 默认为 true\n\n // 非 SPA 模式或 URL 没有变化,且已经初始化过,直接返回\n if (sdkInitPromise && (!isSpa || currentInitUrl === signatureUrl)) {\n return sdkInitPromise\n }\n\n // URL 变化或首次初始化\n currentInitUrl = signatureUrl\n\n sdkInitPromise = (async () => {\n // 获取签名\n const signatureResult = await cfg.getSignature(signatureUrl)\n\n // 调用 wx.config\n const wx = getWx()\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: cfg.debug ?? false,\n appId: signatureResult.appId,\n timestamp: signatureResult.timestamp,\n nonceStr: signatureResult.nonceStr,\n signature: signatureResult.signature,\n jsApiList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n // 初始化失败,清除缓存以便下次重试\n sdkInitPromise = null\n currentInitUrl = null\n reject(new Error(`wx.config failed: ${res.errMsg}`))\n })\n })\n })()\n\n return sdkInitPromise\n}\n\n/**\n * 重置 SDK 状态(用于测试或强制重新初始化)\n */\nexport function resetSDK(): void {\n sdkInitPromise = null\n currentInitUrl = null\n entryUrl = null\n}\n","import { initSDK, getWx } from './sdk'\n\n/**\n * 分享参数\n */\nexport interface ShareOptions {\n /** 分享标题 */\n title: string\n /** 分享描述(分享给朋友时显示) */\n desc?: string\n /** 分享链接,默认为当前页面 URL */\n link?: string\n /** 分享图标 URL */\n imgUrl: string\n}\n\nconst SHARE_JS_API_LIST = [\n 'updateAppMessageShareData',\n 'updateTimelineShareData',\n]\n\n/**\n * 设置微信分享内容\n * 会自动加载 SDK 并初始化,然后设置分享内容\n * @param options - 分享参数\n */\nexport async function share(options: ShareOptions): Promise<void> {\n // 确保 SDK 已初始化\n await initSDK(SHARE_JS_API_LIST)\n\n const wx = getWx()\n const link = options.link ?? (typeof window !== 'undefined' ? window.location.href : '')\n\n // 设置分享给朋友\n await new Promise<void>((resolve, reject) => {\n wx.updateAppMessageShareData({\n title: options.title,\n desc: options.desc ?? '',\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateAppMessageShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n\n // 设置分享到朋友圈\n await new Promise<void>((resolve, reject) => {\n wx.updateTimelineShareData({\n title: options.title,\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateTimelineShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n}\n","/**\n * 微信 JS-SDK wx.config 所需的配置参数\n */\nexport interface Config {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n /** 需要使用的 JS 接口列表 */\n jsApiList: string[]\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /** 需要使用的开放标签列表 */\n openTagList?: string[]\n}\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n}\n\n/**\n * 初始化微信 JS-SDK,调用 wx.config 并返回 Promise\n * 注意:使用此函数前,需要在 HTML 中提前引入微信 JS-SDK 脚本,确保 window.wx 可用\n * @param config - 微信 JS-SDK 配置参数\n * @returns Promise,ready 时 resolve,error 时 reject 并携带错误信息\n */\nexport function init(config: Config): Promise<void> {\n if (typeof window === 'undefined') {\n return Promise.reject(new Error('init: window is not defined'))\n }\n\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n return Promise.reject(new Error('init: wx is not defined, please load WeChat JS-SDK first'))\n }\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: config.debug ?? false,\n appId: config.appId,\n timestamp: config.timestamp,\n nonceStr: config.nonceStr,\n signature: config.signature,\n jsApiList: config.jsApiList,\n openTagList: config.openTagList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n reject(new Error(`init: ${res.errMsg}`))\n })\n })\n}\n"]} | ||
| {"version":3,"sources":["../src/config.ts","../src/sdk.ts","../src/share.ts","../src/init.ts"],"names":["config"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 微信 JS-SDK 签名参数\n */\nexport interface SignatureResult {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n}\n\n/**\n * 内置签名接口返回值\n */\ninterface BuiltInSignatureResponse {\n code: number\n data: {\n app_id: string\n timestamp: number\n nonce_str: string\n signature: string\n }\n message: string\n}\n\n/**\n * 支持内置签名的域名列表\n */\nconst BUILT_IN_SIGNATURE_DOMAINS = [\n 'https://act.go.sohu.com',\n 'https://test.r.ads.sohu.com',\n]\n\n/**\n * 检查当前域名是否支持内置签名\n */\nfunction isBuiltInSignatureDomain(): boolean {\n if (typeof window === 'undefined') return false\n const origin = window.location.origin\n return BUILT_IN_SIGNATURE_DOMAINS.includes(origin)\n}\n\n/**\n * 发起 HTTP GET 请求,支持 fetch 和 XMLHttpRequest 回退\n */\nasync function httpGet(url: string): Promise<BuiltInSignatureResponse> {\n // 优先使用 fetch API\n if (typeof fetch !== 'undefined') {\n const response = await fetch(url)\n\n if (!response.ok) {\n throw new Error(`Failed to fetch signature: ${response.status} ${response.statusText}`)\n }\n\n return await response.json()\n }\n\n // 回退到 XMLHttpRequest\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest()\n xhr.open('GET', url, true)\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const result = JSON.parse(xhr.responseText)\n resolve(result)\n } catch (error) {\n reject(new Error(`Failed to parse response: ${error}`))\n }\n } else {\n reject(new Error(`Failed to fetch signature: ${xhr.status} ${xhr.statusText}`))\n }\n }\n\n xhr.onerror = () => {\n reject(new Error('Network error occurred'))\n }\n\n xhr.send()\n })\n}\n\n/**\n * 内置的签名获取函数(仅在特定域名下可用)\n */\nasync function builtInGetSignature(url: string): Promise<SignatureResult> {\n const apiUrl = `/wechat/ticket?url=${encodeURIComponent(url)}`\n const result = await httpGet(apiUrl)\n\n if (result.code !== 0) {\n throw new Error(`Signature API error: ${result.message}`)\n }\n\n return {\n appId: result.data.app_id,\n timestamp: result.data.timestamp,\n nonceStr: result.data.nonce_str,\n signature: result.data.signature,\n }\n}\n\n/**\n * 全局配置选项\n */\nexport interface GlobalConfig {\n /**\n * 获取签名参数的函数,接收当前页面 URL,返回签名参数\n * - 在 https://act.go.sohu.com 或 https://test.r.ads.sohu.com 域名下,此参数可选\n * - 未提供时将自动使用内置签名获取函数(请求 /wechat/ticket)\n * - 在其他域名下,此参数必填\n */\n getSignature?: (url: string) => Promise<SignatureResult>\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /**\n * 是否为 SPA 单页应用模式,默认 true\n * - true: 每次调用 API 时检测 URL 变化,变化则重新初始化\n * - false: 仅初始化一次\n */\n spa?: boolean\n}\n\nlet globalConfig: GlobalConfig | null = null\n\n/**\n * 设置全局配置\n * @param options - 配置选项\n */\nexport function config(options: GlobalConfig = {}): void {\n // 如果未提供 getSignature,尝试使用内置签名函数\n if (!options.getSignature) {\n if (isBuiltInSignatureDomain()) {\n options.getSignature = builtInGetSignature\n // 设置默认值,确保未初始化时也有合理的默认配置\n if (options.debug === undefined) {\n options.debug = false\n }\n if (options.spa === undefined) {\n options.spa = true\n }\n } else {\n throw new Error(\n '当前域名不支持内置签名,请提供 getSignature 函数。' +\n '内置签名仅在以下域名下可用:' +\n BUILT_IN_SIGNATURE_DOMAINS.join(', ')\n )\n }\n }\n\n globalConfig = options as Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig\n}\n\n/**\n * 获取全局配置\n * @returns 全局配置,如果未配置则尝试自动初始化(仅在支持的域名下)\n */\nexport function getConfig(): Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig {\n if (!globalConfig) {\n // 在支持的域名下,自动初始化默认配置\n if (isBuiltInSignatureDomain()) {\n config({})\n } else {\n throw new Error(\n '请先调用 config() 进行配置。' +\n '在 ' +\n BUILT_IN_SIGNATURE_DOMAINS.join(', ') +\n ' 域名下可以自动使用内置配置。'\n )\n }\n }\n return globalConfig as Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig\n}\n\n/**\n * 检查是否已配置\n */\nexport function isConfigured(): boolean {\n return globalConfig !== null\n}\n\n/**\n * 重置配置(仅用于测试)\n * @internal\n */\nexport function resetConfig(): void {\n globalConfig = null\n}\n","import { getConfig } from './config'\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n updateAppMessageShareData: (options: {\n title: string\n desc: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n updateTimelineShareData: (options: {\n title: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n}\n\nlet sdkInitPromise: Promise<void> | null = null\nlet currentInitUrl: string | null = null\nlet entryUrl: string | null = null // iOS 微信需要用首次进入的 URL\n\n/**\n * 检测是否为 iOS 微信浏览器\n */\nfunction isIOSWechat(): boolean {\n if (typeof navigator === 'undefined') return false\n const ua = navigator.userAgent.toLowerCase()\n return /iphone|ipad|ipod/.test(ua) && /micromessenger/.test(ua)\n}\n\n/**\n * 获取用于签名的 URL\n * iOS 微信需要用首次进入页面的 URL,Android 用当前 URL\n */\nfunction getSignatureUrl(): string {\n if (typeof window === 'undefined') return ''\n\n const currentUrl = window.location.href.split('#')[0]\n\n if (isIOSWechat()) {\n // iOS 微信:用首次进入的 URL\n if (!entryUrl) {\n entryUrl = currentUrl\n }\n return entryUrl\n }\n\n // Android 或其他:用当前 URL\n return currentUrl\n}\n\n/**\n * 获取 wx 对象\n */\nexport function getWx(): WxSDK {\n if (typeof window === 'undefined') {\n throw new Error('window is not defined')\n }\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n throw new Error('wx is not defined')\n }\n return wx\n}\n\n/**\n * 初始化 SDK(获取签名并调用 wx.config)\n * SPA 模式下,URL 变化时会重新初始化(Android)\n * iOS 微信始终使用首次进入的 URL 进行签名\n * 注意:需要使用者在全局引入微信 JS-SDK,确保 window.wx 可用\n */\nexport async function initSDK(jsApiList: string[]): Promise<void> {\n const cfg = getConfig()\n const signatureUrl = getSignatureUrl()\n const isSpa = cfg.spa !== false // 默认为 true\n\n // 非 SPA 模式或 URL 没有变化,且已经初始化过,直接返回\n if (sdkInitPromise && (!isSpa || currentInitUrl === signatureUrl)) {\n return sdkInitPromise\n }\n\n // URL 变化或首次初始化\n currentInitUrl = signatureUrl\n\n sdkInitPromise = (async () => {\n // 获取签名\n const signatureResult = await cfg.getSignature(signatureUrl)\n\n // 调用 wx.config\n const wx = getWx()\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: cfg.debug ?? false,\n appId: signatureResult.appId,\n timestamp: signatureResult.timestamp,\n nonceStr: signatureResult.nonceStr,\n signature: signatureResult.signature,\n jsApiList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n // 初始化失败,清除缓存以便下次重试\n sdkInitPromise = null\n currentInitUrl = null\n reject(new Error(`wx.config failed: ${res.errMsg}`))\n })\n })\n })()\n\n return sdkInitPromise\n}\n\n/**\n * 重置 SDK 状态(用于测试或强制重新初始化)\n */\nexport function resetSDK(): void {\n sdkInitPromise = null\n currentInitUrl = null\n entryUrl = null\n}\n","import { initSDK, getWx } from './sdk'\n\n/**\n * 分享参数\n */\nexport interface ShareOptions {\n /** 分享标题 */\n title: string\n /** 分享描述(分享给朋友时显示) */\n desc?: string\n /** 分享链接,默认为当前页面 URL */\n link?: string\n /** 分享图标 URL */\n imgUrl: string\n}\n\nconst SHARE_JS_API_LIST = [\n 'updateAppMessageShareData',\n 'updateTimelineShareData',\n]\n\n/**\n * 设置微信分享内容\n * 会自动加载 SDK 并初始化,然后设置分享内容\n * @param options - 分享参数\n */\nexport async function share(options: ShareOptions): Promise<void> {\n // 确保 SDK 已初始化\n await initSDK(SHARE_JS_API_LIST)\n\n const wx = getWx()\n const link = options.link ?? (typeof window !== 'undefined' ? window.location.href : '')\n\n // 设置分享给朋友\n await new Promise<void>((resolve, reject) => {\n wx.updateAppMessageShareData({\n title: options.title,\n desc: options.desc ?? '',\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateAppMessageShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n\n // 设置分享到朋友圈\n await new Promise<void>((resolve, reject) => {\n wx.updateTimelineShareData({\n title: options.title,\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateTimelineShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n}\n","/**\n * 微信 JS-SDK wx.config 所需的配置参数\n */\nexport interface Config {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n /** 需要使用的 JS 接口列表 */\n jsApiList: string[]\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /** 需要使用的开放标签列表 */\n openTagList?: string[]\n}\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n}\n\n/**\n * 初始化微信 JS-SDK,调用 wx.config 并返回 Promise\n * 注意:使用此函数前,需要在 HTML 中提前引入微信 JS-SDK 脚本,确保 window.wx 可用\n * @param config - 微信 JS-SDK 配置参数\n * @returns Promise,ready 时 resolve,error 时 reject 并携带错误信息\n */\nexport function init(config: Config): Promise<void> {\n if (typeof window === 'undefined') {\n return Promise.reject(new Error('init: window is not defined'))\n }\n\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n return Promise.reject(new Error('init: wx is not defined, please load WeChat JS-SDK first'))\n }\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: config.debug ?? false,\n appId: config.appId,\n timestamp: config.timestamp,\n nonceStr: config.nonceStr,\n signature: config.signature,\n jsApiList: config.jsApiList,\n openTagList: config.openTagList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n reject(new Error(`init: ${res.errMsg}`))\n })\n })\n}\n"]} |
+74
-2
| // src/config.ts | ||
| var BUILT_IN_SIGNATURE_DOMAINS = [ | ||
| "https://act.go.sohu.com", | ||
| "https://test.r.ads.sohu.com" | ||
| ]; | ||
| function isBuiltInSignatureDomain() { | ||
| if (typeof window === "undefined") return false; | ||
| const origin = window.location.origin; | ||
| return BUILT_IN_SIGNATURE_DOMAINS.includes(origin); | ||
| } | ||
| async function httpGet(url) { | ||
| if (typeof fetch !== "undefined") { | ||
| const response = await fetch(url); | ||
| if (!response.ok) { | ||
| throw new Error(`Failed to fetch signature: ${response.status} ${response.statusText}`); | ||
| } | ||
| return await response.json(); | ||
| } | ||
| return new Promise((resolve, reject) => { | ||
| const xhr = new XMLHttpRequest(); | ||
| xhr.open("GET", url, true); | ||
| xhr.onload = () => { | ||
| if (xhr.status >= 200 && xhr.status < 300) { | ||
| try { | ||
| const result = JSON.parse(xhr.responseText); | ||
| resolve(result); | ||
| } catch (error) { | ||
| reject(new Error(`Failed to parse response: ${error}`)); | ||
| } | ||
| } else { | ||
| reject(new Error(`Failed to fetch signature: ${xhr.status} ${xhr.statusText}`)); | ||
| } | ||
| }; | ||
| xhr.onerror = () => { | ||
| reject(new Error("Network error occurred")); | ||
| }; | ||
| xhr.send(); | ||
| }); | ||
| } | ||
| async function builtInGetSignature(url) { | ||
| const apiUrl = `/wechat/ticket?url=${encodeURIComponent(url)}`; | ||
| const result = await httpGet(apiUrl); | ||
| if (result.code !== 0) { | ||
| throw new Error(`Signature API error: ${result.message}`); | ||
| } | ||
| return { | ||
| appId: result.data.app_id, | ||
| timestamp: result.data.timestamp, | ||
| nonceStr: result.data.nonce_str, | ||
| signature: result.data.signature | ||
| }; | ||
| } | ||
| var globalConfig = null; | ||
| function config(options) { | ||
| function config(options = {}) { | ||
| if (!options.getSignature) { | ||
| if (isBuiltInSignatureDomain()) { | ||
| options.getSignature = builtInGetSignature; | ||
| if (options.debug === void 0) { | ||
| options.debug = false; | ||
| } | ||
| if (options.spa === void 0) { | ||
| options.spa = true; | ||
| } | ||
| } else { | ||
| throw new Error( | ||
| "\u5F53\u524D\u57DF\u540D\u4E0D\u652F\u6301\u5185\u7F6E\u7B7E\u540D\uFF0C\u8BF7\u63D0\u4F9B getSignature \u51FD\u6570\u3002\u5185\u7F6E\u7B7E\u540D\u4EC5\u5728\u4EE5\u4E0B\u57DF\u540D\u4E0B\u53EF\u7528\uFF1A" + BUILT_IN_SIGNATURE_DOMAINS.join(", ") | ||
| ); | ||
| } | ||
| } | ||
| globalConfig = options; | ||
@@ -8,3 +74,9 @@ } | ||
| if (!globalConfig) { | ||
| throw new Error("\u8BF7\u5148\u8C03\u7528 config() \u8FDB\u884C\u914D\u7F6E"); | ||
| if (isBuiltInSignatureDomain()) { | ||
| config({}); | ||
| } else { | ||
| throw new Error( | ||
| "\u8BF7\u5148\u8C03\u7528 config() \u8FDB\u884C\u914D\u7F6E\u3002\u5728 " + BUILT_IN_SIGNATURE_DOMAINS.join(", ") + " \u57DF\u540D\u4E0B\u53EF\u4EE5\u81EA\u52A8\u4F7F\u7528\u5185\u7F6E\u914D\u7F6E\u3002" | ||
| ); | ||
| } | ||
| } | ||
@@ -11,0 +83,0 @@ return globalConfig; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"sources":["../src/config.ts","../src/sdk.ts","../src/share.ts","../src/init.ts"],"names":["config"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * 微信 JS-SDK 签名参数\n */\nexport interface SignatureResult {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n}\n\n/**\n * 全局配置选项\n */\nexport interface GlobalConfig {\n /** 获取签名参数的函数,接收当前页面 URL,返回签名参数 */\n getSignature: (url: string) => Promise<SignatureResult>\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /**\n * 是否为 SPA 单页应用模式,默认 true\n * - true: 每次调用 API 时检测 URL 变化,变化则重新初始化\n * - false: 仅初始化一次\n */\n spa?: boolean\n}\n\nlet globalConfig: GlobalConfig | null = null\n\n/**\n * 设置全局配置\n * @param options - 配置选项\n */\nexport function config(options: GlobalConfig): void {\n globalConfig = options\n}\n\n/**\n * 获取全局配置\n * @returns 全局配置,如果未配置则抛出错误\n */\nexport function getConfig(): GlobalConfig {\n if (!globalConfig) {\n throw new Error('请先调用 config() 进行配置')\n }\n return globalConfig\n}\n\n/**\n * 检查是否已配置\n */\nexport function isConfigured(): boolean {\n return globalConfig !== null\n}\n","import { getConfig } from './config'\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n updateAppMessageShareData: (options: {\n title: string\n desc: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n updateTimelineShareData: (options: {\n title: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n}\n\nlet sdkInitPromise: Promise<void> | null = null\nlet currentInitUrl: string | null = null\nlet entryUrl: string | null = null // iOS 微信需要用首次进入的 URL\n\n/**\n * 检测是否为 iOS 微信浏览器\n */\nfunction isIOSWechat(): boolean {\n if (typeof navigator === 'undefined') return false\n const ua = navigator.userAgent.toLowerCase()\n return /iphone|ipad|ipod/.test(ua) && /micromessenger/.test(ua)\n}\n\n/**\n * 获取用于签名的 URL\n * iOS 微信需要用首次进入页面的 URL,Android 用当前 URL\n */\nfunction getSignatureUrl(): string {\n if (typeof window === 'undefined') return ''\n\n const currentUrl = window.location.href.split('#')[0]\n\n if (isIOSWechat()) {\n // iOS 微信:用首次进入的 URL\n if (!entryUrl) {\n entryUrl = currentUrl\n }\n return entryUrl\n }\n\n // Android 或其他:用当前 URL\n return currentUrl\n}\n\n/**\n * 获取 wx 对象\n */\nexport function getWx(): WxSDK {\n if (typeof window === 'undefined') {\n throw new Error('window is not defined')\n }\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n throw new Error('wx is not defined')\n }\n return wx\n}\n\n/**\n * 初始化 SDK(获取签名并调用 wx.config)\n * SPA 模式下,URL 变化时会重新初始化(Android)\n * iOS 微信始终使用首次进入的 URL 进行签名\n * 注意:需要使用者在全局引入微信 JS-SDK,确保 window.wx 可用\n */\nexport async function initSDK(jsApiList: string[]): Promise<void> {\n const cfg = getConfig()\n const signatureUrl = getSignatureUrl()\n const isSpa = cfg.spa !== false // 默认为 true\n\n // 非 SPA 模式或 URL 没有变化,且已经初始化过,直接返回\n if (sdkInitPromise && (!isSpa || currentInitUrl === signatureUrl)) {\n return sdkInitPromise\n }\n\n // URL 变化或首次初始化\n currentInitUrl = signatureUrl\n\n sdkInitPromise = (async () => {\n // 获取签名\n const signatureResult = await cfg.getSignature(signatureUrl)\n\n // 调用 wx.config\n const wx = getWx()\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: cfg.debug ?? false,\n appId: signatureResult.appId,\n timestamp: signatureResult.timestamp,\n nonceStr: signatureResult.nonceStr,\n signature: signatureResult.signature,\n jsApiList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n // 初始化失败,清除缓存以便下次重试\n sdkInitPromise = null\n currentInitUrl = null\n reject(new Error(`wx.config failed: ${res.errMsg}`))\n })\n })\n })()\n\n return sdkInitPromise\n}\n\n/**\n * 重置 SDK 状态(用于测试或强制重新初始化)\n */\nexport function resetSDK(): void {\n sdkInitPromise = null\n currentInitUrl = null\n entryUrl = null\n}\n","import { initSDK, getWx } from './sdk'\n\n/**\n * 分享参数\n */\nexport interface ShareOptions {\n /** 分享标题 */\n title: string\n /** 分享描述(分享给朋友时显示) */\n desc?: string\n /** 分享链接,默认为当前页面 URL */\n link?: string\n /** 分享图标 URL */\n imgUrl: string\n}\n\nconst SHARE_JS_API_LIST = [\n 'updateAppMessageShareData',\n 'updateTimelineShareData',\n]\n\n/**\n * 设置微信分享内容\n * 会自动加载 SDK 并初始化,然后设置分享内容\n * @param options - 分享参数\n */\nexport async function share(options: ShareOptions): Promise<void> {\n // 确保 SDK 已初始化\n await initSDK(SHARE_JS_API_LIST)\n\n const wx = getWx()\n const link = options.link ?? (typeof window !== 'undefined' ? window.location.href : '')\n\n // 设置分享给朋友\n await new Promise<void>((resolve, reject) => {\n wx.updateAppMessageShareData({\n title: options.title,\n desc: options.desc ?? '',\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateAppMessageShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n\n // 设置分享到朋友圈\n await new Promise<void>((resolve, reject) => {\n wx.updateTimelineShareData({\n title: options.title,\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateTimelineShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n}\n","/**\n * 微信 JS-SDK wx.config 所需的配置参数\n */\nexport interface Config {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n /** 需要使用的 JS 接口列表 */\n jsApiList: string[]\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /** 需要使用的开放标签列表 */\n openTagList?: string[]\n}\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n}\n\n/**\n * 初始化微信 JS-SDK,调用 wx.config 并返回 Promise\n * 注意:使用此函数前,需要在 HTML 中提前引入微信 JS-SDK 脚本,确保 window.wx 可用\n * @param config - 微信 JS-SDK 配置参数\n * @returns Promise,ready 时 resolve,error 时 reject 并携带错误信息\n */\nexport function init(config: Config): Promise<void> {\n if (typeof window === 'undefined') {\n return Promise.reject(new Error('init: window is not defined'))\n }\n\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n return Promise.reject(new Error('init: wx is not defined, please load WeChat JS-SDK first'))\n }\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: config.debug ?? false,\n appId: config.appId,\n timestamp: config.timestamp,\n nonceStr: config.nonceStr,\n signature: config.signature,\n jsApiList: config.jsApiList,\n openTagList: config.openTagList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n reject(new Error(`init: ${res.errMsg}`))\n })\n })\n}\n"]} | ||
| {"version":3,"sources":["../src/config.ts","../src/sdk.ts","../src/share.ts","../src/init.ts"],"names":["config"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * 微信 JS-SDK 签名参数\n */\nexport interface SignatureResult {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n}\n\n/**\n * 内置签名接口返回值\n */\ninterface BuiltInSignatureResponse {\n code: number\n data: {\n app_id: string\n timestamp: number\n nonce_str: string\n signature: string\n }\n message: string\n}\n\n/**\n * 支持内置签名的域名列表\n */\nconst BUILT_IN_SIGNATURE_DOMAINS = [\n 'https://act.go.sohu.com',\n 'https://test.r.ads.sohu.com',\n]\n\n/**\n * 检查当前域名是否支持内置签名\n */\nfunction isBuiltInSignatureDomain(): boolean {\n if (typeof window === 'undefined') return false\n const origin = window.location.origin\n return BUILT_IN_SIGNATURE_DOMAINS.includes(origin)\n}\n\n/**\n * 发起 HTTP GET 请求,支持 fetch 和 XMLHttpRequest 回退\n */\nasync function httpGet(url: string): Promise<BuiltInSignatureResponse> {\n // 优先使用 fetch API\n if (typeof fetch !== 'undefined') {\n const response = await fetch(url)\n\n if (!response.ok) {\n throw new Error(`Failed to fetch signature: ${response.status} ${response.statusText}`)\n }\n\n return await response.json()\n }\n\n // 回退到 XMLHttpRequest\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest()\n xhr.open('GET', url, true)\n\n xhr.onload = () => {\n if (xhr.status >= 200 && xhr.status < 300) {\n try {\n const result = JSON.parse(xhr.responseText)\n resolve(result)\n } catch (error) {\n reject(new Error(`Failed to parse response: ${error}`))\n }\n } else {\n reject(new Error(`Failed to fetch signature: ${xhr.status} ${xhr.statusText}`))\n }\n }\n\n xhr.onerror = () => {\n reject(new Error('Network error occurred'))\n }\n\n xhr.send()\n })\n}\n\n/**\n * 内置的签名获取函数(仅在特定域名下可用)\n */\nasync function builtInGetSignature(url: string): Promise<SignatureResult> {\n const apiUrl = `/wechat/ticket?url=${encodeURIComponent(url)}`\n const result = await httpGet(apiUrl)\n\n if (result.code !== 0) {\n throw new Error(`Signature API error: ${result.message}`)\n }\n\n return {\n appId: result.data.app_id,\n timestamp: result.data.timestamp,\n nonceStr: result.data.nonce_str,\n signature: result.data.signature,\n }\n}\n\n/**\n * 全局配置选项\n */\nexport interface GlobalConfig {\n /**\n * 获取签名参数的函数,接收当前页面 URL,返回签名参数\n * - 在 https://act.go.sohu.com 或 https://test.r.ads.sohu.com 域名下,此参数可选\n * - 未提供时将自动使用内置签名获取函数(请求 /wechat/ticket)\n * - 在其他域名下,此参数必填\n */\n getSignature?: (url: string) => Promise<SignatureResult>\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /**\n * 是否为 SPA 单页应用模式,默认 true\n * - true: 每次调用 API 时检测 URL 变化,变化则重新初始化\n * - false: 仅初始化一次\n */\n spa?: boolean\n}\n\nlet globalConfig: GlobalConfig | null = null\n\n/**\n * 设置全局配置\n * @param options - 配置选项\n */\nexport function config(options: GlobalConfig = {}): void {\n // 如果未提供 getSignature,尝试使用内置签名函数\n if (!options.getSignature) {\n if (isBuiltInSignatureDomain()) {\n options.getSignature = builtInGetSignature\n // 设置默认值,确保未初始化时也有合理的默认配置\n if (options.debug === undefined) {\n options.debug = false\n }\n if (options.spa === undefined) {\n options.spa = true\n }\n } else {\n throw new Error(\n '当前域名不支持内置签名,请提供 getSignature 函数。' +\n '内置签名仅在以下域名下可用:' +\n BUILT_IN_SIGNATURE_DOMAINS.join(', ')\n )\n }\n }\n\n globalConfig = options as Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig\n}\n\n/**\n * 获取全局配置\n * @returns 全局配置,如果未配置则尝试自动初始化(仅在支持的域名下)\n */\nexport function getConfig(): Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig {\n if (!globalConfig) {\n // 在支持的域名下,自动初始化默认配置\n if (isBuiltInSignatureDomain()) {\n config({})\n } else {\n throw new Error(\n '请先调用 config() 进行配置。' +\n '在 ' +\n BUILT_IN_SIGNATURE_DOMAINS.join(', ') +\n ' 域名下可以自动使用内置配置。'\n )\n }\n }\n return globalConfig as Required<Pick<GlobalConfig, 'getSignature'>> & GlobalConfig\n}\n\n/**\n * 检查是否已配置\n */\nexport function isConfigured(): boolean {\n return globalConfig !== null\n}\n\n/**\n * 重置配置(仅用于测试)\n * @internal\n */\nexport function resetConfig(): void {\n globalConfig = null\n}\n","import { getConfig } from './config'\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n updateAppMessageShareData: (options: {\n title: string\n desc: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n updateTimelineShareData: (options: {\n title: string\n link: string\n imgUrl: string\n success?: () => void\n fail?: (err: { errMsg: string }) => void\n }) => void\n}\n\nlet sdkInitPromise: Promise<void> | null = null\nlet currentInitUrl: string | null = null\nlet entryUrl: string | null = null // iOS 微信需要用首次进入的 URL\n\n/**\n * 检测是否为 iOS 微信浏览器\n */\nfunction isIOSWechat(): boolean {\n if (typeof navigator === 'undefined') return false\n const ua = navigator.userAgent.toLowerCase()\n return /iphone|ipad|ipod/.test(ua) && /micromessenger/.test(ua)\n}\n\n/**\n * 获取用于签名的 URL\n * iOS 微信需要用首次进入页面的 URL,Android 用当前 URL\n */\nfunction getSignatureUrl(): string {\n if (typeof window === 'undefined') return ''\n\n const currentUrl = window.location.href.split('#')[0]\n\n if (isIOSWechat()) {\n // iOS 微信:用首次进入的 URL\n if (!entryUrl) {\n entryUrl = currentUrl\n }\n return entryUrl\n }\n\n // Android 或其他:用当前 URL\n return currentUrl\n}\n\n/**\n * 获取 wx 对象\n */\nexport function getWx(): WxSDK {\n if (typeof window === 'undefined') {\n throw new Error('window is not defined')\n }\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n throw new Error('wx is not defined')\n }\n return wx\n}\n\n/**\n * 初始化 SDK(获取签名并调用 wx.config)\n * SPA 模式下,URL 变化时会重新初始化(Android)\n * iOS 微信始终使用首次进入的 URL 进行签名\n * 注意:需要使用者在全局引入微信 JS-SDK,确保 window.wx 可用\n */\nexport async function initSDK(jsApiList: string[]): Promise<void> {\n const cfg = getConfig()\n const signatureUrl = getSignatureUrl()\n const isSpa = cfg.spa !== false // 默认为 true\n\n // 非 SPA 模式或 URL 没有变化,且已经初始化过,直接返回\n if (sdkInitPromise && (!isSpa || currentInitUrl === signatureUrl)) {\n return sdkInitPromise\n }\n\n // URL 变化或首次初始化\n currentInitUrl = signatureUrl\n\n sdkInitPromise = (async () => {\n // 获取签名\n const signatureResult = await cfg.getSignature(signatureUrl)\n\n // 调用 wx.config\n const wx = getWx()\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: cfg.debug ?? false,\n appId: signatureResult.appId,\n timestamp: signatureResult.timestamp,\n nonceStr: signatureResult.nonceStr,\n signature: signatureResult.signature,\n jsApiList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n // 初始化失败,清除缓存以便下次重试\n sdkInitPromise = null\n currentInitUrl = null\n reject(new Error(`wx.config failed: ${res.errMsg}`))\n })\n })\n })()\n\n return sdkInitPromise\n}\n\n/**\n * 重置 SDK 状态(用于测试或强制重新初始化)\n */\nexport function resetSDK(): void {\n sdkInitPromise = null\n currentInitUrl = null\n entryUrl = null\n}\n","import { initSDK, getWx } from './sdk'\n\n/**\n * 分享参数\n */\nexport interface ShareOptions {\n /** 分享标题 */\n title: string\n /** 分享描述(分享给朋友时显示) */\n desc?: string\n /** 分享链接,默认为当前页面 URL */\n link?: string\n /** 分享图标 URL */\n imgUrl: string\n}\n\nconst SHARE_JS_API_LIST = [\n 'updateAppMessageShareData',\n 'updateTimelineShareData',\n]\n\n/**\n * 设置微信分享内容\n * 会自动加载 SDK 并初始化,然后设置分享内容\n * @param options - 分享参数\n */\nexport async function share(options: ShareOptions): Promise<void> {\n // 确保 SDK 已初始化\n await initSDK(SHARE_JS_API_LIST)\n\n const wx = getWx()\n const link = options.link ?? (typeof window !== 'undefined' ? window.location.href : '')\n\n // 设置分享给朋友\n await new Promise<void>((resolve, reject) => {\n wx.updateAppMessageShareData({\n title: options.title,\n desc: options.desc ?? '',\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateAppMessageShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n\n // 设置分享到朋友圈\n await new Promise<void>((resolve, reject) => {\n wx.updateTimelineShareData({\n title: options.title,\n link,\n imgUrl: options.imgUrl,\n success: () => resolve(),\n fail: (err) => reject(new Error(`updateTimelineShareData failed: ${err.errMsg}`)),\n })\n // 微信 SDK 有时不会调用 success/fail,设置超时自动 resolve\n setTimeout(resolve, 500)\n })\n}\n","/**\n * 微信 JS-SDK wx.config 所需的配置参数\n */\nexport interface Config {\n /** 公众号的 appId */\n appId: string\n /** 生成签名的时间戳 */\n timestamp: number | string\n /** 生成签名的随机字符串 */\n nonceStr: string\n /** 签名 */\n signature: string\n /** 需要使用的 JS 接口列表 */\n jsApiList: string[]\n /** 是否开启调试模式,默认 false */\n debug?: boolean\n /** 需要使用的开放标签列表 */\n openTagList?: string[]\n}\n\ninterface WxSDK {\n config: (cfg: {\n debug: boolean\n appId: string\n timestamp: number | string\n nonceStr: string\n signature: string\n jsApiList: string[]\n openTagList?: string[]\n }) => void\n ready: (fn: () => void) => void\n error: (fn: (res: { errMsg: string }) => void) => void\n}\n\n/**\n * 初始化微信 JS-SDK,调用 wx.config 并返回 Promise\n * 注意:使用此函数前,需要在 HTML 中提前引入微信 JS-SDK 脚本,确保 window.wx 可用\n * @param config - 微信 JS-SDK 配置参数\n * @returns Promise,ready 时 resolve,error 时 reject 并携带错误信息\n */\nexport function init(config: Config): Promise<void> {\n if (typeof window === 'undefined') {\n return Promise.reject(new Error('init: window is not defined'))\n }\n\n const wx = (window as unknown as Record<string, unknown>).wx as WxSDK | undefined\n if (!wx) {\n return Promise.reject(new Error('init: wx is not defined, please load WeChat JS-SDK first'))\n }\n\n return new Promise<void>((resolve, reject) => {\n wx.config({\n debug: config.debug ?? false,\n appId: config.appId,\n timestamp: config.timestamp,\n nonceStr: config.nonceStr,\n signature: config.signature,\n jsApiList: config.jsApiList,\n openTagList: config.openTagList,\n })\n\n wx.ready(() => {\n resolve()\n })\n\n wx.error((res: { errMsg: string }) => {\n reject(new Error(`init: ${res.errMsg}`))\n })\n })\n}\n"]} |
+1
-1
| { | ||
| "name": "@sohu-bpd/wechat", | ||
| "version": "0.0.4", | ||
| "version": "0.0.5", | ||
| "description": "WeChat JS-SDK utility library", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
+180
-6
@@ -33,8 +33,41 @@ # @sohu-bpd/wechat | ||
| ### 2. Configure Once | ||
| ### 2. Configure (Optional on Sohu Domains) | ||
| **Option A: Zero Configuration (Sohu Domains Only)** | ||
| If you're on `https://act.go.sohu.com` or `https://test.r.ads.sohu.com`, you can skip configuration entirely: | ||
| ```typescript | ||
| import { share } from '@sohu-bpd/wechat' | ||
| // No config needed! Just use it directly | ||
| await share({ | ||
| title: 'My Page Title', | ||
| desc: 'Share description', | ||
| imgUrl: 'https://example.com/image.jpg', | ||
| }) | ||
| ``` | ||
| **Option B: Custom Configuration (Sohu Domains)** | ||
| Or customize settings on supported domains: | ||
| ```typescript | ||
| import { config } from '@sohu-bpd/wechat' | ||
| // No need to provide getSignature on supported domains | ||
| config({ | ||
| debug: false, | ||
| spa: true, // Enable SPA mode (default) | ||
| }) | ||
| ``` | ||
| **Option C: Custom Signature Function (Other Domains)** | ||
| For other domains or custom backends: | ||
| ```typescript | ||
| import { config } from '@sohu-bpd/wechat' | ||
| config({ | ||
| getSignature: async (url) => { | ||
@@ -108,8 +141,15 @@ // Fetch signature from your backend | ||
| **Note:** You must load the WeChat JS-SDK script in your HTML before using this library. | ||
| **Note:** | ||
| - You must load the WeChat JS-SDK script in your HTML before using this library | ||
| - **On `https://act.go.sohu.com` or `https://test.r.ads.sohu.com`, calling `config()` is optional** - the library will auto-configure with defaults when you use features like `share()` | ||
| ```typescript | ||
| interface GlobalConfig { | ||
| /** Function to fetch signature, receives current URL */ | ||
| getSignature: (url: string) => Promise<SignatureResult> | ||
| /** | ||
| * Function to fetch signature, receives current URL | ||
| * - Optional on https://act.go.sohu.com or https://test.r.ads.sohu.com | ||
| * - Will auto-use built-in signature (requests /wechat/ticket) if not provided | ||
| * - Required on other domains | ||
| */ | ||
| getSignature?: (url: string) => Promise<SignatureResult> | ||
| /** Enable debug mode, default false */ | ||
@@ -121,8 +161,21 @@ debug?: boolean | ||
| function config(options: GlobalConfig): void | ||
| function config(options?: GlobalConfig): void | ||
| ``` | ||
| **Example:** | ||
| **Example - No configuration needed (Sohu domains):** | ||
| ```typescript | ||
| import { share } from '@sohu-bpd/wechat' | ||
| // Just use it directly! | ||
| await share({ | ||
| title: 'My Page', | ||
| desc: 'Description', | ||
| imgUrl: 'https://example.com/image.jpg', | ||
| }) | ||
| ``` | ||
| **Example - Custom signature function:** | ||
| ```typescript | ||
| config({ | ||
@@ -138,2 +191,12 @@ getSignature: async (url) => { | ||
| **Example - Custom settings with built-in signature (Sohu domains):** | ||
| ```typescript | ||
| // On https://act.go.sohu.com or https://test.r.ads.sohu.com | ||
| config({ | ||
| debug: true, | ||
| spa: true, | ||
| }) | ||
| ``` | ||
| #### share(options) | ||
@@ -257,2 +320,104 @@ | ||
| ## Built-in Signature Support | ||
| On specific Sohu domains, the library provides built-in signature functionality: | ||
| ### Supported Domains | ||
| - `https://act.go.sohu.com` | ||
| - `https://test.r.ads.sohu.com` | ||
| ### How It Works | ||
| When you call `config()` without providing `getSignature` on a supported domain: | ||
| 1. The library automatically detects the current domain | ||
| 2. Uses the built-in signature function that requests `/wechat/ticket` | ||
| 3. Converts the API response to the standard `SignatureResult` format | ||
| ### API Request Format | ||
| The built-in signature function sends a GET request to: | ||
| ``` | ||
| /wechat/ticket?url={encoded_current_url} | ||
| ``` | ||
| **Parameters:** | ||
| - `url` (query parameter): The current page URL (URL-encoded) | ||
| **Example Request:** | ||
| ``` | ||
| GET /wechat/ticket?url=https%3A%2F%2Fact.go.sohu.com%2Fpage%3Fid%3D123 | ||
| ``` | ||
| ### API Response Format | ||
| The built-in signature endpoint `/wechat/ticket` should return: | ||
| ```typescript | ||
| { | ||
| code: number // 0 for success | ||
| data: { | ||
| app_id: string // Converted to appId | ||
| timestamp: number // Kept as timestamp | ||
| nonce_str: string // Converted to nonceStr | ||
| signature: string // Kept as signature | ||
| } | ||
| message: string // Error message if code !== 0 | ||
| } | ||
| ``` | ||
| **Notes:** | ||
| - Uses `fetch` API if available (modern browsers) | ||
| - Automatically falls back to `XMLHttpRequest` in older environments | ||
| - Response format is automatically converted to match `SignatureResult` interface | ||
| ### Usage | ||
| **Zero Configuration (Recommended):** | ||
| ```typescript | ||
| import { share } from '@sohu-bpd/wechat' | ||
| // No config() needed on supported domains! | ||
| await share({ | ||
| title: 'My Page', | ||
| desc: 'Description', | ||
| imgUrl: 'https://example.com/image.jpg', | ||
| }) | ||
| ``` | ||
| **With Custom Settings:** | ||
| ```typescript | ||
| import { config, share } from '@sohu-bpd/wechat' | ||
| // Optional: customize settings | ||
| config({ | ||
| debug: true, | ||
| spa: true, | ||
| }) | ||
| // Then use normally | ||
| await share({ | ||
| title: 'My Page', | ||
| desc: 'Description', | ||
| imgUrl: 'https://example.com/image.jpg', | ||
| }) | ||
| ``` | ||
| ### Fallback to Custom Function | ||
| Even on supported domains, you can provide your own `getSignature` function: | ||
| ```typescript | ||
| config({ | ||
| getSignature: async (url) => { | ||
| // Your custom implementation | ||
| return await fetchSignatureFromCustomAPI(url) | ||
| }, | ||
| }) | ||
| ``` | ||
| ## iOS WeChat Quirk | ||
@@ -317,2 +482,11 @@ | ||
| ### 0.0.4 (TBD) | ||
| - **New Feature:** Built-in signature support for Sohu domains | ||
| - **Zero Configuration Mode:** On `https://act.go.sohu.com` and `https://test.r.ads.sohu.com`, you can now use the library without calling `config()` at all | ||
| - `getSignature` is now optional on supported domains | ||
| - Automatic signature fetching from `/wechat/ticket?url={current_url}` endpoint on supported domains | ||
| - Built-in request uses `fetch` API with automatic fallback to `XMLHttpRequest` for older browsers | ||
| - Added comprehensive tests for built-in signature functionality, xhr fallback, and auto-initialization | ||
| ### 0.0.3 (2026-01-29) | ||
@@ -319,0 +493,0 @@ |
Network access
Supply chain riskThis module accesses the network.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
98964
45.56%800
38.17%508
52.1%2
100%6
Infinity%