支付
This commit is contained in:
162
dist/index.d.ts
vendored
162
dist/index.d.ts
vendored
@@ -53,14 +53,6 @@ interface ScanConfigOptions {
|
|||||||
* 是否允许 H5 摄像头扫码:true 强制开启(仍需有媒体 API),false 强制关闭
|
* 是否允许 H5 摄像头扫码:true 强制开启(仍需有媒体 API),false 强制关闭
|
||||||
*/
|
*/
|
||||||
webScanCameraEnabled?: boolean,
|
webScanCameraEnabled?: boolean,
|
||||||
/**
|
|
||||||
* @deprecated 请用 webScanCameraEnabled;保留兼容
|
|
||||||
*/
|
|
||||||
webScanCameraInWechat?: boolean,
|
|
||||||
/**
|
|
||||||
* @deprecated 摄像头权限已后置到 startScan,请用 webScanVideoAccessTimeout
|
|
||||||
*/
|
|
||||||
webScanCameraProbeTimeout?: number,
|
|
||||||
/**
|
/**
|
||||||
* startScan 走 Web 摄像头前是否展示权限说明弹窗,默认 true
|
* startScan 走 Web 摄像头前是否展示权限说明弹窗,默认 true
|
||||||
*/
|
*/
|
||||||
@@ -196,6 +188,68 @@ interface ScanConfigOptions {
|
|||||||
* 扫码成功是否播放提示音,默认启用;任意识别模式匹配成功时生效
|
* 扫码成功是否播放提示音,默认启用;任意识别模式匹配成功时生效
|
||||||
*/
|
*/
|
||||||
scanBeepEnabled?: boolean,
|
scanBeepEnabled?: boolean,
|
||||||
|
/**
|
||||||
|
* PC 微信 Native 扫码支付是否展示内置二维码弹层,默认 true
|
||||||
|
*/
|
||||||
|
paymentNativeQrEnabled?: boolean,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层标题
|
||||||
|
*/
|
||||||
|
paymentNativeQrTitle?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层说明文案
|
||||||
|
*/
|
||||||
|
paymentNativeQrMessage?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码底部提示
|
||||||
|
*/
|
||||||
|
paymentNativeQrHint?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码边长(像素),默认 220
|
||||||
|
*/
|
||||||
|
paymentNativeQrSize?: number,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层遮罩样式
|
||||||
|
*/
|
||||||
|
paymentNativeQrOverlayStyle?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层面板样式
|
||||||
|
*/
|
||||||
|
paymentNativeQrPanelStyle?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码关闭按钮样式
|
||||||
|
*/
|
||||||
|
paymentNativeQrCloseButtonStyle?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层遮罩 class
|
||||||
|
*/
|
||||||
|
paymentNativeQrOverlayClass?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层面板 class
|
||||||
|
*/
|
||||||
|
paymentNativeQrPanelClass?: string,
|
||||||
|
/**
|
||||||
|
* 微信支付 OAuth 配置(paymentType 为 wechat 且微信内 JSAPI 时由 requestPayment 自动处理)
|
||||||
|
*/
|
||||||
|
initWechatPayment?: {
|
||||||
|
/**
|
||||||
|
* 用 code 换 openid,对应 api.biz.wechat.oauth
|
||||||
|
*/
|
||||||
|
oauthApiUrl?: string,
|
||||||
|
/**
|
||||||
|
* 获取 OAuth 授权信息(含 appId、authorizeUrl),对应 api.biz.wechat.oauthAuthorizeUrl
|
||||||
|
*/
|
||||||
|
oauthAuthorizeUrlApiUrl?: string,
|
||||||
|
/**
|
||||||
|
* openid 缓存 key,默认 iscan_wechat_openid_${appId}(appId 来自授权接口响应)
|
||||||
|
*/
|
||||||
|
storageKey?: string,
|
||||||
|
/**
|
||||||
|
* OAuth 授权回跳完整 URL(redirectUri),须与当前页域名一致且已在公众号登记;
|
||||||
|
* 未配置时默认使用当前页 location.href(不含 hash)
|
||||||
|
*/
|
||||||
|
redirectUri?: string,
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 微信JSSDK配置,微信环境才会生效,配置后会自动初始化微信JSSDK
|
* 微信JSSDK配置,微信环境才会生效,配置后会自动初始化微信JSSDK
|
||||||
*/
|
*/
|
||||||
@@ -319,6 +373,79 @@ interface ScanErrorListenerInfo {
|
|||||||
*/
|
*/
|
||||||
type ScanStatusCallback = (status: ScanStatus) => any;
|
type ScanStatusCallback = (status: ScanStatus) => any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付渠道
|
||||||
|
*/
|
||||||
|
type PaymentType = 'wechat' | 'alipay';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSAPI 收银台交互结果(仅表示用户在收银台的操作,非支付到账结果)
|
||||||
|
*/
|
||||||
|
type PaymentCashierResult = 'ok' | 'cancel' | 'fail';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付场景
|
||||||
|
*/
|
||||||
|
type PayScene = 'jsapi' | 'h5' | 'native';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDK 传给业务支付函数的参数(OAuth、环境判断由 SDK 自动完成)
|
||||||
|
*/
|
||||||
|
interface PaymentPrepareParams {
|
||||||
|
/** 微信 JSAPI 场景下的 openid,其他场景为空字符串 */
|
||||||
|
openid: string;
|
||||||
|
/** 当前环境对应的微信支付场景 */
|
||||||
|
payScene: PayScene;
|
||||||
|
/** navigator.userAgent */
|
||||||
|
userAgent: string;
|
||||||
|
/** 用户 IP,默认空字符串 */
|
||||||
|
clientIp: string;
|
||||||
|
/** 支付完成回跳地址 */
|
||||||
|
returnUrl: string;
|
||||||
|
/** 支付渠道 */
|
||||||
|
paymentType: PaymentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务支付函数:调用自己的支付接口,返回 paymentFormData
|
||||||
|
*/
|
||||||
|
type PaymentFormDataProvider = (
|
||||||
|
params: PaymentPrepareParams
|
||||||
|
) => string | Record<string, any> | Promise<string | Record<string, any>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDK 发起支付后的返回(不代表支付成功,业务须自行查单)
|
||||||
|
*/
|
||||||
|
interface PaymentInvokeResult {
|
||||||
|
payType?: 'jsapi' | 'h5' | 'native' | 'alipay';
|
||||||
|
/** SDK 是否已发起支付流程 */
|
||||||
|
invoked: boolean;
|
||||||
|
/** 微信 OAuth 授权跳转中(页面将刷新,业务函数尚未执行) */
|
||||||
|
oauthRedirecting?: boolean;
|
||||||
|
/** 支付未发起(含微信 OAuth 失败) */
|
||||||
|
failed?: boolean;
|
||||||
|
/** 微信 OAuth / openid 获取失败 */
|
||||||
|
oauthFailed?: boolean;
|
||||||
|
/** OAuth 或调起失败时的错误信息 */
|
||||||
|
error?: string;
|
||||||
|
/** H5 / 支付宝是否已跳转 */
|
||||||
|
redirected?: boolean;
|
||||||
|
/** Native 场景是否展示了二维码弹层 */
|
||||||
|
qrShown?: boolean;
|
||||||
|
/** 微信 JSAPI 收银台交互结果(非支付到账结果) */
|
||||||
|
cashierResult?: PaymentCashierResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付请求选项
|
||||||
|
*/
|
||||||
|
interface RequestPaymentOptions {
|
||||||
|
/** 支付完成回跳地址,未传时使用当前页 URL */
|
||||||
|
returnUrl?: string;
|
||||||
|
/** OAuth 授权回跳完整 URL(redirectUri),覆盖 initWechatPayment.redirectUri */
|
||||||
|
redirectUri?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/** IScan */
|
/** IScan */
|
||||||
interface IScan {
|
interface IScan {
|
||||||
/**
|
/**
|
||||||
@@ -377,12 +504,29 @@ interface IScan {
|
|||||||
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
|
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
|
||||||
*/
|
*/
|
||||||
scanImage(key?: string): void;
|
scanImage(key?: string): void;
|
||||||
/** 由业务/原生传入已选图片 File 识别(WebView input.files 异常时使用) */
|
/**
|
||||||
|
* 由业务/原生传入已选图片 File 识别(WebView input.files 异常时使用)
|
||||||
|
* @param file 已选图片 File
|
||||||
|
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
|
||||||
|
*/
|
||||||
scanImageFromFile(file: File | Blob, key?: string): void;
|
scanImageFromFile(file: File | Blob, key?: string): void;
|
||||||
/**
|
/**
|
||||||
* 清除全部监听
|
* 清除全部监听
|
||||||
*/
|
*/
|
||||||
clear(): void;
|
clear(): void;
|
||||||
|
/**
|
||||||
|
* 发起支付:按 paymentType 决定是否走微信 OAuth,再将参数传给业务函数获取 paymentFormData 并调起支付。
|
||||||
|
* 不代表支付成功,业务须自行查单。
|
||||||
|
*/
|
||||||
|
requestPayment(
|
||||||
|
paymentType: PaymentType,
|
||||||
|
fetchPaymentFormData: PaymentFormDataProvider,
|
||||||
|
options?: RequestPaymentOptions
|
||||||
|
): Promise<PaymentInvokeResult>;
|
||||||
|
/**
|
||||||
|
* 关闭 SDK 管理的支付相关 UI(如 PC Native 二维码弹层)
|
||||||
|
*/
|
||||||
|
closePaymentDialog(): void;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
dist/index.js
vendored
2
dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -51,5 +51,8 @@
|
|||||||
},
|
},
|
||||||
"repository": {},
|
"repository": {},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC"
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"qrcode": "^1.5.4"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
154
pnpm-lock.yaml
generated
154
pnpm-lock.yaml
generated
@@ -7,6 +7,10 @@ settings:
|
|||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
|
dependencies:
|
||||||
|
qrcode:
|
||||||
|
specifier: ^1.5.4
|
||||||
|
version: 1.5.4
|
||||||
devDependencies:
|
devDependencies:
|
||||||
autoprefixer:
|
autoprefixer:
|
||||||
specifier: ^7.2.3
|
specifier: ^7.2.3
|
||||||
@@ -243,6 +247,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==}
|
resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
ansi-regex@5.0.1:
|
||||||
|
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
ansi-styles@2.2.1:
|
ansi-styles@2.2.1:
|
||||||
resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
|
resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -251,6 +259,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
|
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
ansi-styles@4.3.0:
|
||||||
|
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
anymatch@2.0.0:
|
anymatch@2.0.0:
|
||||||
resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==}
|
resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==}
|
||||||
|
|
||||||
@@ -762,6 +774,9 @@ packages:
|
|||||||
cliui@5.0.0:
|
cliui@5.0.0:
|
||||||
resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==}
|
resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==}
|
||||||
|
|
||||||
|
cliui@6.0.0:
|
||||||
|
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
|
||||||
|
|
||||||
clone@1.0.4:
|
clone@1.0.4:
|
||||||
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
|
||||||
engines: {node: '>=0.8'}
|
engines: {node: '>=0.8'}
|
||||||
@@ -781,6 +796,10 @@ packages:
|
|||||||
color-convert@1.9.3:
|
color-convert@1.9.3:
|
||||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||||
|
|
||||||
|
color-convert@2.0.1:
|
||||||
|
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||||
|
engines: {node: '>=7.0.0'}
|
||||||
|
|
||||||
color-name@1.1.3:
|
color-name@1.1.3:
|
||||||
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
|
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
|
||||||
|
|
||||||
@@ -1051,6 +1070,9 @@ packages:
|
|||||||
diffie-hellman@5.0.3:
|
diffie-hellman@5.0.3:
|
||||||
resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==}
|
resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==}
|
||||||
|
|
||||||
|
dijkstrajs@1.0.3:
|
||||||
|
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||||
|
|
||||||
dom-converter@0.2.0:
|
dom-converter@0.2.0:
|
||||||
resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==}
|
resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==}
|
||||||
|
|
||||||
@@ -1108,6 +1130,9 @@ packages:
|
|||||||
emoji-regex@7.0.3:
|
emoji-regex@7.0.3:
|
||||||
resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==}
|
resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==}
|
||||||
|
|
||||||
|
emoji-regex@8.0.0:
|
||||||
|
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||||
|
|
||||||
emojis-list@3.0.0:
|
emojis-list@3.0.0:
|
||||||
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
|
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
@@ -1305,6 +1330,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
|
resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
find-up@4.1.0:
|
||||||
|
resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
findup-sync@3.0.0:
|
findup-sync@3.0.0:
|
||||||
resolution: {integrity: sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==}
|
resolution: {integrity: sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
@@ -1776,6 +1805,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==}
|
resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
is-fullwidth-code-point@3.0.0:
|
||||||
|
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
is-generator-function@1.1.2:
|
is-generator-function@1.1.2:
|
||||||
resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==}
|
resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -1989,6 +2022,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
|
resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
locate-path@5.0.0:
|
||||||
|
resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
lodash.camelcase@4.3.0:
|
lodash.camelcase@4.3.0:
|
||||||
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
|
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
|
||||||
|
|
||||||
@@ -2276,6 +2313,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
|
resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
p-locate@4.1.0:
|
||||||
|
resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
p-map@2.1.0:
|
p-map@2.1.0:
|
||||||
resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
|
resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2333,6 +2374,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
|
resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
path-exists@4.0.0:
|
||||||
|
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
path-is-absolute@1.0.1:
|
path-is-absolute@1.0.1:
|
||||||
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -2397,6 +2442,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==}
|
resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==}
|
||||||
engines: {node: '>=4.0.0'}
|
engines: {node: '>=4.0.0'}
|
||||||
|
|
||||||
|
pngjs@5.0.0:
|
||||||
|
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
portfinder@1.0.38:
|
portfinder@1.0.38:
|
||||||
resolution: {integrity: sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==}
|
resolution: {integrity: sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==}
|
||||||
engines: {node: '>= 10.12'}
|
engines: {node: '>= 10.12'}
|
||||||
@@ -2587,6 +2636,11 @@ packages:
|
|||||||
|
|
||||||
(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)
|
(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)
|
||||||
|
|
||||||
|
qrcode@1.5.4:
|
||||||
|
resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
qs@2.3.3:
|
qs@2.3.3:
|
||||||
resolution: {integrity: sha512-f5M0HQqZWkzU8GELTY8LyMrGkr3bPjKoFtTkwUEqJQbcljbeK8M7mliP9Ia2xoOI6oMerp+QPS7oYJtpGmWe/A==}
|
resolution: {integrity: sha512-f5M0HQqZWkzU8GELTY8LyMrGkr3bPjKoFtTkwUEqJQbcljbeK8M7mliP9Ia2xoOI6oMerp+QPS7oYJtpGmWe/A==}
|
||||||
|
|
||||||
@@ -2985,6 +3039,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==}
|
resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
string-width@4.2.3:
|
||||||
|
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
string.prototype.trim@1.2.10:
|
string.prototype.trim@1.2.10:
|
||||||
resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
|
resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -3011,6 +3069,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==}
|
resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
strip-ansi@6.0.1:
|
||||||
|
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
strip-bom@3.0.0:
|
strip-bom@3.0.0:
|
||||||
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
@@ -3352,6 +3414,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==}
|
resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
wrap-ansi@6.2.0:
|
||||||
|
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
wrappy@1.0.2:
|
wrappy@1.0.2:
|
||||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||||
|
|
||||||
@@ -3382,9 +3448,17 @@ packages:
|
|||||||
yargs-parser@13.1.2:
|
yargs-parser@13.1.2:
|
||||||
resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==}
|
resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==}
|
||||||
|
|
||||||
|
yargs-parser@18.1.3:
|
||||||
|
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
yargs@13.3.2:
|
yargs@13.3.2:
|
||||||
resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==}
|
resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==}
|
||||||
|
|
||||||
|
yargs@15.4.1:
|
||||||
|
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
zxing-wasm@3.0.2:
|
zxing-wasm@3.0.2:
|
||||||
resolution: {integrity: sha512-2YMAriaYHX9wrBY2k7H0epSo+dyCaCZg/vOtt+nEDXM9ul480gkXz/9SkwpOeHcD2H5qqDG8lWDSBwpTcZpa6w==}
|
resolution: {integrity: sha512-2YMAriaYHX9wrBY2k7H0epSo+dyCaCZg/vOtt+nEDXM9ul480gkXz/9SkwpOeHcD2H5qqDG8lWDSBwpTcZpa6w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3566,12 +3640,18 @@ snapshots:
|
|||||||
|
|
||||||
ansi-regex@4.1.1: {}
|
ansi-regex@4.1.1: {}
|
||||||
|
|
||||||
|
ansi-regex@5.0.1: {}
|
||||||
|
|
||||||
ansi-styles@2.2.1: {}
|
ansi-styles@2.2.1: {}
|
||||||
|
|
||||||
ansi-styles@3.2.1:
|
ansi-styles@3.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
color-convert: 1.9.3
|
color-convert: 1.9.3
|
||||||
|
|
||||||
|
ansi-styles@4.3.0:
|
||||||
|
dependencies:
|
||||||
|
color-convert: 2.0.1
|
||||||
|
|
||||||
anymatch@2.0.0:
|
anymatch@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
micromatch: 3.1.10(supports-color@6.1.0)
|
micromatch: 3.1.10(supports-color@6.1.0)
|
||||||
@@ -4473,6 +4553,12 @@ snapshots:
|
|||||||
strip-ansi: 5.2.0
|
strip-ansi: 5.2.0
|
||||||
wrap-ansi: 5.1.0
|
wrap-ansi: 5.1.0
|
||||||
|
|
||||||
|
cliui@6.0.0:
|
||||||
|
dependencies:
|
||||||
|
string-width: 4.2.3
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
wrap-ansi: 6.2.0
|
||||||
|
|
||||||
clone@1.0.4: {}
|
clone@1.0.4: {}
|
||||||
|
|
||||||
co@4.6.0: {}
|
co@4.6.0: {}
|
||||||
@@ -4490,6 +4576,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-name: 1.1.3
|
color-name: 1.1.3
|
||||||
|
|
||||||
|
color-convert@2.0.1:
|
||||||
|
dependencies:
|
||||||
|
color-name: 1.1.4
|
||||||
|
|
||||||
color-name@1.1.3: {}
|
color-name@1.1.3: {}
|
||||||
|
|
||||||
color-name@1.1.4: {}
|
color-name@1.1.4: {}
|
||||||
@@ -4826,6 +4916,8 @@ snapshots:
|
|||||||
miller-rabin: 4.0.1
|
miller-rabin: 4.0.1
|
||||||
randombytes: 2.1.0
|
randombytes: 2.1.0
|
||||||
|
|
||||||
|
dijkstrajs@1.0.3: {}
|
||||||
|
|
||||||
dom-converter@0.2.0:
|
dom-converter@0.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
utila: 0.4.0
|
utila: 0.4.0
|
||||||
@@ -4900,6 +4992,8 @@ snapshots:
|
|||||||
|
|
||||||
emoji-regex@7.0.3: {}
|
emoji-regex@7.0.3: {}
|
||||||
|
|
||||||
|
emoji-regex@8.0.0: {}
|
||||||
|
|
||||||
emojis-list@3.0.0: {}
|
emojis-list@3.0.0: {}
|
||||||
|
|
||||||
encodeurl@2.0.0: {}
|
encodeurl@2.0.0: {}
|
||||||
@@ -5188,6 +5282,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
locate-path: 3.0.0
|
locate-path: 3.0.0
|
||||||
|
|
||||||
|
find-up@4.1.0:
|
||||||
|
dependencies:
|
||||||
|
locate-path: 5.0.0
|
||||||
|
path-exists: 4.0.0
|
||||||
|
|
||||||
findup-sync@3.0.0(supports-color@6.1.0):
|
findup-sync@3.0.0(supports-color@6.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
detect-file: 1.0.0
|
detect-file: 1.0.0
|
||||||
@@ -5712,6 +5811,8 @@ snapshots:
|
|||||||
|
|
||||||
is-fullwidth-code-point@2.0.0: {}
|
is-fullwidth-code-point@2.0.0: {}
|
||||||
|
|
||||||
|
is-fullwidth-code-point@3.0.0: {}
|
||||||
|
|
||||||
is-generator-function@1.1.2:
|
is-generator-function@1.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
@@ -5906,6 +6007,10 @@ snapshots:
|
|||||||
p-locate: 3.0.0
|
p-locate: 3.0.0
|
||||||
path-exists: 3.0.0
|
path-exists: 3.0.0
|
||||||
|
|
||||||
|
locate-path@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
p-locate: 4.1.0
|
||||||
|
|
||||||
lodash.camelcase@4.3.0: {}
|
lodash.camelcase@4.3.0: {}
|
||||||
|
|
||||||
lodash.memoize@4.1.2: {}
|
lodash.memoize@4.1.2: {}
|
||||||
@@ -6256,6 +6361,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
p-limit: 2.3.0
|
p-limit: 2.3.0
|
||||||
|
|
||||||
|
p-locate@4.1.0:
|
||||||
|
dependencies:
|
||||||
|
p-limit: 2.3.0
|
||||||
|
|
||||||
p-map@2.1.0: {}
|
p-map@2.1.0: {}
|
||||||
|
|
||||||
p-try@1.0.0: {}
|
p-try@1.0.0: {}
|
||||||
@@ -6310,6 +6419,8 @@ snapshots:
|
|||||||
|
|
||||||
path-exists@3.0.0: {}
|
path-exists@3.0.0: {}
|
||||||
|
|
||||||
|
path-exists@4.0.0: {}
|
||||||
|
|
||||||
path-is-absolute@1.0.1: {}
|
path-is-absolute@1.0.1: {}
|
||||||
|
|
||||||
path-is-inside@1.0.2: {}
|
path-is-inside@1.0.2: {}
|
||||||
@@ -6359,6 +6470,8 @@ snapshots:
|
|||||||
|
|
||||||
pngjs@3.4.0: {}
|
pngjs@3.4.0: {}
|
||||||
|
|
||||||
|
pngjs@5.0.0: {}
|
||||||
|
|
||||||
portfinder@1.0.38:
|
portfinder@1.0.38:
|
||||||
dependencies:
|
dependencies:
|
||||||
async: 3.2.6
|
async: 3.2.6
|
||||||
@@ -6620,6 +6733,12 @@ snapshots:
|
|||||||
|
|
||||||
q@1.5.1: {}
|
q@1.5.1: {}
|
||||||
|
|
||||||
|
qrcode@1.5.4:
|
||||||
|
dependencies:
|
||||||
|
dijkstrajs: 1.0.3
|
||||||
|
pngjs: 5.0.0
|
||||||
|
yargs: 15.4.1
|
||||||
|
|
||||||
qs@2.3.3: {}
|
qs@2.3.3: {}
|
||||||
|
|
||||||
qs@6.14.2:
|
qs@6.14.2:
|
||||||
@@ -7137,6 +7256,12 @@ snapshots:
|
|||||||
is-fullwidth-code-point: 2.0.0
|
is-fullwidth-code-point: 2.0.0
|
||||||
strip-ansi: 5.2.0
|
strip-ansi: 5.2.0
|
||||||
|
|
||||||
|
string-width@4.2.3:
|
||||||
|
dependencies:
|
||||||
|
emoji-regex: 8.0.0
|
||||||
|
is-fullwidth-code-point: 3.0.0
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
|
||||||
string.prototype.trim@1.2.10:
|
string.prototype.trim@1.2.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.9
|
call-bind: 1.0.9
|
||||||
@@ -7176,6 +7301,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ansi-regex: 4.1.1
|
ansi-regex: 4.1.1
|
||||||
|
|
||||||
|
strip-ansi@6.0.1:
|
||||||
|
dependencies:
|
||||||
|
ansi-regex: 5.0.1
|
||||||
|
|
||||||
strip-bom@3.0.0: {}
|
strip-bom@3.0.0: {}
|
||||||
|
|
||||||
style-loader@0.18.2:
|
style-loader@0.18.2:
|
||||||
@@ -7612,6 +7741,12 @@ snapshots:
|
|||||||
string-width: 3.1.0
|
string-width: 3.1.0
|
||||||
strip-ansi: 5.2.0
|
strip-ansi: 5.2.0
|
||||||
|
|
||||||
|
wrap-ansi@6.2.0:
|
||||||
|
dependencies:
|
||||||
|
ansi-styles: 4.3.0
|
||||||
|
string-width: 4.2.3
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
|
||||||
wrappy@1.0.2: {}
|
wrappy@1.0.2: {}
|
||||||
|
|
||||||
ws@6.2.3:
|
ws@6.2.3:
|
||||||
@@ -7631,6 +7766,11 @@ snapshots:
|
|||||||
camelcase: 5.3.1
|
camelcase: 5.3.1
|
||||||
decamelize: 1.2.0
|
decamelize: 1.2.0
|
||||||
|
|
||||||
|
yargs-parser@18.1.3:
|
||||||
|
dependencies:
|
||||||
|
camelcase: 5.3.1
|
||||||
|
decamelize: 1.2.0
|
||||||
|
|
||||||
yargs@13.3.2:
|
yargs@13.3.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
cliui: 5.0.0
|
cliui: 5.0.0
|
||||||
@@ -7644,6 +7784,20 @@ snapshots:
|
|||||||
y18n: 4.0.3
|
y18n: 4.0.3
|
||||||
yargs-parser: 13.1.2
|
yargs-parser: 13.1.2
|
||||||
|
|
||||||
|
yargs@15.4.1:
|
||||||
|
dependencies:
|
||||||
|
cliui: 6.0.0
|
||||||
|
decamelize: 1.2.0
|
||||||
|
find-up: 4.1.0
|
||||||
|
get-caller-file: 2.0.5
|
||||||
|
require-directory: 2.1.1
|
||||||
|
require-main-filename: 2.0.0
|
||||||
|
set-blocking: 2.0.0
|
||||||
|
string-width: 4.2.3
|
||||||
|
which-module: 2.0.1
|
||||||
|
y18n: 4.0.3
|
||||||
|
yargs-parser: 18.1.3
|
||||||
|
|
||||||
zxing-wasm@3.0.2(@types/emscripten@1.41.5):
|
zxing-wasm@3.0.2(@types/emscripten@1.41.5):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/emscripten': 1.41.5
|
'@types/emscripten': 1.41.5
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
isSupportImageScan
|
isSupportImageScan
|
||||||
} from './services/web';
|
} from './services/web';
|
||||||
import { printDebug, printWarn } from './utils/logger';
|
import { printDebug, printWarn } from './utils/logger';
|
||||||
|
import { requestPayment, closePaymentDialog } from './services/payment';
|
||||||
|
|
||||||
let _readyPromise = null;
|
let _readyPromise = null;
|
||||||
let _calledReady = false;
|
let _calledReady = false;
|
||||||
@@ -65,4 +66,6 @@ export default Object.assign({}, {
|
|||||||
scanImage,
|
scanImage,
|
||||||
scanImageFromFile,
|
scanImageFromFile,
|
||||||
clear,
|
clear,
|
||||||
|
requestPayment,
|
||||||
|
closePaymentDialog,
|
||||||
});
|
});
|
||||||
@@ -50,6 +50,7 @@ function isEmbedMessage(data) {
|
|||||||
let embedHostInstalled = false;
|
let embedHostInstalled = false;
|
||||||
let embedChildInstalled = false;
|
let embedChildInstalled = false;
|
||||||
const pendingInvokes = Object.create(null);
|
const pendingInvokes = Object.create(null);
|
||||||
|
const pendingCallbackInvokes = Object.create(null);
|
||||||
const childCallbackFns = Object.create(null);
|
const childCallbackFns = Object.create(null);
|
||||||
|
|
||||||
function cloneArgsReplacingFunctions(val, registry, seen) {
|
function cloneArgsReplacingFunctions(val, registry, seen) {
|
||||||
@@ -93,16 +94,21 @@ function hydrateEmbedParams(params, messageSource, targetOrigin) {
|
|||||||
const cbId = val.__IScanEmbedCb__;
|
const cbId = val.__IScanEmbedCb__;
|
||||||
return function embedCbProxy() {
|
return function embedCbProxy() {
|
||||||
const args = Array.prototype.slice.call(arguments);
|
const args = Array.prototype.slice.call(arguments);
|
||||||
|
const callbackInvokeId = createUUID();
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
pendingCallbackInvokes[callbackInvokeId] = { resolve, reject };
|
||||||
messageSource.postMessage(
|
messageSource.postMessage(
|
||||||
{
|
{
|
||||||
source: EMBED_SOURCE,
|
source: EMBED_SOURCE,
|
||||||
v: EMBED_V,
|
v: EMBED_V,
|
||||||
kind: "callback",
|
kind: "callback",
|
||||||
cbId,
|
cbId,
|
||||||
|
callbackInvokeId,
|
||||||
args,
|
args,
|
||||||
},
|
},
|
||||||
targetOrigin
|
targetOrigin
|
||||||
);
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (val === null || typeof val !== "object") {
|
if (val === null || typeof val !== "object") {
|
||||||
@@ -262,9 +268,35 @@ function embedChildOnMessage(ev) {
|
|||||||
}
|
}
|
||||||
if (data.kind === "callback") {
|
if (data.kind === "callback") {
|
||||||
const fn = childCallbackFns[data.cbId];
|
const fn = childCallbackFns[data.cbId];
|
||||||
if (typeof fn === "function") {
|
const replyCallbackResult = (ok, result, error) => {
|
||||||
fn.apply(null, data.args || []);
|
if (!data.callbackInvokeId || !ev.source) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
ev.source.postMessage(
|
||||||
|
{
|
||||||
|
source: EMBED_SOURCE,
|
||||||
|
v: EMBED_V,
|
||||||
|
kind: "callbackResult",
|
||||||
|
callbackInvokeId: data.callbackInvokeId,
|
||||||
|
ok,
|
||||||
|
result: ok ? result : undefined,
|
||||||
|
error: ok ? undefined : error,
|
||||||
|
},
|
||||||
|
ev.origin
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if (typeof fn !== "function") {
|
||||||
|
replyCallbackResult(false, null, "[IScan embed]: callback not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Promise.resolve(fn.apply(null, data.args || []))
|
||||||
|
.then((result) => {
|
||||||
|
replyCallbackResult(true, result);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
replyCallbackResult(false, null, String((err && err.message) || err));
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,6 +422,19 @@ export function installEmbedHost(lib) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (data.kind === "callbackResult") {
|
||||||
|
const pending = pendingCallbackInvokes[data.callbackInvokeId];
|
||||||
|
if (!pending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete pendingCallbackInvokes[data.callbackInvokeId];
|
||||||
|
if (data.ok) {
|
||||||
|
pending.resolve(data.result);
|
||||||
|
} else {
|
||||||
|
pending.reject(new Error(data.error || "[IScan embed]: callback failed"));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (data.kind !== "invoke") {
|
if (data.kind !== "invoke") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ if (typeof document !== 'undefined' && document.currentScript && document.curren
|
|||||||
}
|
}
|
||||||
|
|
||||||
const IScan = exportSDK(core, null, "config", "setStatusListener", "onScanListener",
|
const IScan = exportSDK(core, null, "config", "setStatusListener", "onScanListener",
|
||||||
"offScanListener", "onScanErrorListener", "offScanErrorListener", "stopScan", "startScan", "scanImage", "scanImageFromFile", "clear");
|
"offScanListener", "onScanErrorListener", "offScanErrorListener", "stopScan", "startScan", "scanImage", "scanImageFromFile", "clear",
|
||||||
|
"requestPayment", "closePaymentDialog");
|
||||||
|
|
||||||
installEmbedHost(core);
|
installEmbedHost(core);
|
||||||
|
|
||||||
|
|||||||
11
src/services/payment/config.js
Normal file
11
src/services/payment/config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { getConfig } from "../config";
|
||||||
|
import { toAny } from "../../utils/toany";
|
||||||
|
|
||||||
|
export function getPaymentConfig() {
|
||||||
|
return toAny(getConfig("initWechatPayment"), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWechatOauthConfigReady() {
|
||||||
|
const cfg = getPaymentConfig();
|
||||||
|
return !!(cfg.oauthApiUrl && cfg.oauthAuthorizeUrlApiUrl);
|
||||||
|
}
|
||||||
41
src/services/payment/env.js
Normal file
41
src/services/payment/env.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { readWxLikeEnvFromWindow, getParentWxEnvReport } from "../embedEnvProbe";
|
||||||
|
import { resolveUseParentProxy } from "../embedProxy";
|
||||||
|
|
||||||
|
export function getTopWindow() {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return window.top || window;
|
||||||
|
} catch (e) {
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWechatBrowser() {
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (readWxLikeEnvFromWindow(topWin)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (typeof window !== "undefined" && readWxLikeEnvFromWindow(window)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (resolveUseParentProxy() && getParentWxEnvReport() === true) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 UA 判断微信支付场景,与后端 payScene=auto 规则一致。
|
||||||
|
*/
|
||||||
|
export function detectPayScene(userAgent) {
|
||||||
|
const ua = userAgent || (typeof navigator !== "undefined" ? navigator.userAgent : "");
|
||||||
|
if (/MicroMessenger/i.test(ua)) {
|
||||||
|
return "jsapi";
|
||||||
|
}
|
||||||
|
if (/Mobile|Android|iPhone|iPad|iPod/i.test(ua)) {
|
||||||
|
return "h5";
|
||||||
|
}
|
||||||
|
return "native";
|
||||||
|
}
|
||||||
297
src/services/payment/index.js
Normal file
297
src/services/payment/index.js
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
import { toAny } from "../../utils/toany";
|
||||||
|
import { getConfig } from "../config";
|
||||||
|
import { getTopWindow, detectPayScene } from "./env";
|
||||||
|
import { showPaymentNativeQrCode, closePaymentNativeQrCode } from "./nativeQrView";
|
||||||
|
import { ensureWechatOpenid } from "./oauth";
|
||||||
|
import { isWechatOauthConfigReady } from "./config";
|
||||||
|
|
||||||
|
function buildInvokeResult(payType, extra) {
|
||||||
|
return Object.assign({ payType, invoked: true }, extra || {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildOAuthRedirectResult() {
|
||||||
|
return { invoked: false, oauthRedirecting: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPaymentFailureResult(error) {
|
||||||
|
const message = error && error.message ? error.message : String(error || "payment failed");
|
||||||
|
return {
|
||||||
|
invoked: false,
|
||||||
|
failed: true,
|
||||||
|
oauthFailed: true,
|
||||||
|
error: message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDefaultReturnUrl() {
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (!topWin || !topWin.location) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return topWin.location.href.split("#")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePaymentType(paymentType) {
|
||||||
|
const type = String(paymentType || "").toLowerCase();
|
||||||
|
if (type !== "wechat" && type !== "alipay") {
|
||||||
|
throw new Error("paymentType must be wechat or alipay");
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPaymentPrepareParams(paymentType, openid, options) {
|
||||||
|
const opts = toAny(options, {});
|
||||||
|
const payScene = detectPayScene();
|
||||||
|
return {
|
||||||
|
openid: paymentType === "wechat" && payScene === "jsapi" ? (openid || "") : "",
|
||||||
|
payScene,
|
||||||
|
userAgent: typeof navigator !== "undefined" ? navigator.userAgent : "",
|
||||||
|
clientIp: "",
|
||||||
|
returnUrl: opts.returnUrl || buildDefaultReturnUrl(),
|
||||||
|
paymentType,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function unwrapPaymentFormData(result) {
|
||||||
|
if (result == null || result === "") {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (typeof result === "string") {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (typeof result === "object") {
|
||||||
|
if (result.paymentFormData != null && result.paymentFormData !== "") {
|
||||||
|
return result.paymentFormData;
|
||||||
|
}
|
||||||
|
if (result.data != null) {
|
||||||
|
if (typeof result.data === "string" && result.data !== "") {
|
||||||
|
return result.data;
|
||||||
|
}
|
||||||
|
if (result.data.paymentFormData != null && result.data.paymentFormData !== "") {
|
||||||
|
return result.data.paymentFormData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result.payType || isAlipayFormHtml(result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldEnsureWechatOAuth(paymentType) {
|
||||||
|
return paymentType === "wechat" && detectPayScene() === "jsapi";
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureOAuthBeforePayment(paymentType, oauthOptions) {
|
||||||
|
if (!shouldEnsureWechatOAuth(paymentType)) {
|
||||||
|
return Promise.resolve("");
|
||||||
|
}
|
||||||
|
if (!isWechatOauthConfigReady()) {
|
||||||
|
return Promise.reject(new Error("initWechatPayment.oauthApiUrl and oauthAuthorizeUrlApiUrl are required for wechat jsapi pay"));
|
||||||
|
}
|
||||||
|
return ensureWechatOpenid(oauthOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAlipayFormHtml(value) {
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const trimmed = value.trim();
|
||||||
|
return /<form[\s>]/i.test(trimmed) || /<input[\s>]/i.test(trimmed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePaymentFormData(paymentFormData, paymentType) {
|
||||||
|
if (paymentType === "alipay" || isAlipayFormHtml(paymentFormData)) {
|
||||||
|
return {
|
||||||
|
type: "alipay",
|
||||||
|
data: typeof paymentFormData === "string" ? paymentFormData : String(paymentFormData || ""),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let formData = paymentFormData;
|
||||||
|
if (typeof formData === "string") {
|
||||||
|
try {
|
||||||
|
formData = JSON.parse(formData);
|
||||||
|
} catch (e) {
|
||||||
|
if (isAlipayFormHtml(formData)) {
|
||||||
|
return { type: "alipay", data: formData };
|
||||||
|
}
|
||||||
|
throw new Error("paymentFormData is not valid JSON");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formData = toAny(formData, {});
|
||||||
|
const payType = formData.payType;
|
||||||
|
if (!payType) {
|
||||||
|
throw new Error("paymentFormData.payType is required");
|
||||||
|
}
|
||||||
|
return { type: String(payType).toLowerCase(), data: formData };
|
||||||
|
}
|
||||||
|
|
||||||
|
function execAlipayPay(html) {
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (!topWin || !topWin.document) {
|
||||||
|
return Promise.reject(new Error("top window document is not available"));
|
||||||
|
}
|
||||||
|
const doc = topWin.document;
|
||||||
|
doc.open();
|
||||||
|
doc.write(html);
|
||||||
|
doc.close();
|
||||||
|
return Promise.resolve(buildInvokeResult("alipay", { redirected: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function execWechatH5Pay(formData) {
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (!topWin) {
|
||||||
|
return Promise.reject(new Error("top window is not available"));
|
||||||
|
}
|
||||||
|
const h5Url = formData.h5Url;
|
||||||
|
if (!h5Url) {
|
||||||
|
return Promise.reject(new Error("paymentFormData.h5Url is required"));
|
||||||
|
}
|
||||||
|
topWin.location.href = h5Url;
|
||||||
|
return Promise.resolve(buildInvokeResult("h5", { redirected: true }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function execWechatNativePay(formData) {
|
||||||
|
const codeUrl = formData.codeUrl;
|
||||||
|
if (!codeUrl) {
|
||||||
|
return Promise.reject(new Error("paymentFormData.codeUrl is required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const showBuiltinQr = getConfig("paymentNativeQrEnabled") !== false;
|
||||||
|
const showPromise = showBuiltinQr
|
||||||
|
? showPaymentNativeQrCode(codeUrl)
|
||||||
|
: Promise.resolve({ shown: false });
|
||||||
|
|
||||||
|
return showPromise.then((qrResult) => {
|
||||||
|
return buildInvokeResult("native", {
|
||||||
|
qrShown: !!(qrResult && qrResult.shown),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function execWechatJsapiPay(formData) {
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (!topWin) {
|
||||||
|
return Promise.reject(new Error("top window is not available"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const payParams = {
|
||||||
|
appId: formData.appId,
|
||||||
|
timeStamp: formData.timeStamp,
|
||||||
|
nonceStr: formData.nonceStr,
|
||||||
|
package: formData.package,
|
||||||
|
signType: formData.signType,
|
||||||
|
paySign: formData.paySign,
|
||||||
|
};
|
||||||
|
|
||||||
|
const requiredKeys = ["appId", "timeStamp", "nonceStr", "package", "signType", "paySign"];
|
||||||
|
for (let i = 0; i < requiredKeys.length; i++) {
|
||||||
|
const key = requiredKeys[i];
|
||||||
|
if (!payParams[key]) {
|
||||||
|
return Promise.reject(new Error(`paymentFormData.${key} is required for jsapi pay`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
function onBridgeReady() {
|
||||||
|
const bridge = topWin.WeixinJSBridge;
|
||||||
|
if (!bridge || !bridge.invoke) {
|
||||||
|
reject(new Error("WeixinJSBridge is not available"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bridge.invoke("getBrandWCPayRequest", payParams, (res) => {
|
||||||
|
const errMsg = res && res.err_msg ? res.err_msg : "";
|
||||||
|
if (errMsg === "get_brand_wcpay_request:ok") {
|
||||||
|
resolve(buildInvokeResult("jsapi", { cashierResult: "ok" }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (errMsg === "get_brand_wcpay_request:cancel") {
|
||||||
|
resolve(buildInvokeResult("jsapi", { cashierResult: "cancel" }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(buildInvokeResult("jsapi", { cashierResult: "fail" }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof topWin.WeixinJSBridge === "undefined") {
|
||||||
|
topWin.document.addEventListener("WeixinJSBridgeReady", onBridgeReady, false);
|
||||||
|
} else {
|
||||||
|
onBridgeReady();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function invokePaymentFormData(paymentFormData, paymentType) {
|
||||||
|
let parsed;
|
||||||
|
try {
|
||||||
|
parsed = normalizePaymentFormData(paymentFormData, paymentType);
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (parsed.type) {
|
||||||
|
case "alipay":
|
||||||
|
return execAlipayPay(parsed.data);
|
||||||
|
case "jsapi":
|
||||||
|
return execWechatJsapiPay(parsed.data);
|
||||||
|
case "h5":
|
||||||
|
return execWechatH5Pay(parsed.data);
|
||||||
|
case "native":
|
||||||
|
return execWechatNativePay(parsed.data);
|
||||||
|
default:
|
||||||
|
return Promise.reject(new Error(`unknown pay type: ${parsed.type}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭 SDK 管理的支付相关 UI(如 PC Native 二维码弹层)。
|
||||||
|
*/
|
||||||
|
export function closePaymentDialog() {
|
||||||
|
closePaymentNativeQrCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起支付:按 paymentType 决定是否走微信 OAuth,再将参数传给业务函数获取 paymentFormData 并调起支付。
|
||||||
|
*/
|
||||||
|
export function requestPayment(paymentType, fetchPaymentFormData, options) {
|
||||||
|
let normalizedPaymentType;
|
||||||
|
try {
|
||||||
|
normalizedPaymentType = normalizePaymentType(paymentType);
|
||||||
|
} catch (err) {
|
||||||
|
return Promise.reject(err);
|
||||||
|
}
|
||||||
|
if (typeof fetchPaymentFormData !== "function") {
|
||||||
|
return Promise.reject(new Error("requestPayment requires a function"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const opts = toAny(options, {});
|
||||||
|
const oauthOptions = {};
|
||||||
|
if (opts.redirectUri) {
|
||||||
|
oauthOptions.redirectUri = opts.redirectUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ensureOAuthBeforePayment(normalizedPaymentType, oauthOptions).then(
|
||||||
|
(openid) => {
|
||||||
|
if (openid === null) {
|
||||||
|
return buildOAuthRedirectResult();
|
||||||
|
}
|
||||||
|
if (shouldEnsureWechatOAuth(normalizedPaymentType) && !openid) {
|
||||||
|
return buildPaymentFailureResult(new Error("wechat openid is empty after oauth"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const prepareParams = buildPaymentPrepareParams(normalizedPaymentType, openid, opts);
|
||||||
|
return Promise.resolve(fetchPaymentFormData(prepareParams)).then((rawResult) => {
|
||||||
|
const paymentFormData = unwrapPaymentFormData(rawResult);
|
||||||
|
if (paymentFormData == null || paymentFormData === "") {
|
||||||
|
return Promise.reject(new Error(
|
||||||
|
`paymentFormData is empty (payScene=${prepareParams.payScene}, check business payment api response)`
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return invokePaymentFormData(paymentFormData, normalizedPaymentType);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(err) => buildPaymentFailureResult(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
153
src/services/payment/nativeQrView.js
Normal file
153
src/services/payment/nativeQrView.js
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
import QRCode from "qrcode";
|
||||||
|
import { getConfig } from "../config";
|
||||||
|
import { getTopWindow } from "./env";
|
||||||
|
|
||||||
|
const OVERLAY_ID = "__iscan_payment_native_qr__";
|
||||||
|
const CLOSE_ICON_SVG = "<svg viewBox=\"0 0 1024 1024\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M566.97558594 521.09667969L856.8828125 231.18945312c14.63378906-14.63378906 14.63378906-38.75976563 0-53.39355468l-1.58203125-1.58203125c-14.63378906-14.63378906-38.75976563-14.63378906-53.39355469 0L512 466.51660156 222.09277344 176.21386719c-14.63378906-14.63378906-38.75976563-14.63378906-53.39355469 0l-1.58203125 1.58203125c-15.02929688 14.63378906-15.02929688 38.75976563 0 53.39355469l289.90722656 289.90722656L167.1171875 811.00390625c-14.63378906 14.63378906-14.63378906 38.75976563 0 53.39355469l1.58203125 1.58203125c14.63378906 14.63378906 38.75976563 14.63378906 53.39355469 0L512 576.07226563 801.90722656 865.97949219c14.63378906 14.63378906 38.75976563 14.63378906 53.39355469 0l1.58203125-1.58203125c14.63378906-14.63378906 14.63378906-38.75976563 0-53.39355469L566.97558594 521.09667969z\" fill=\"currentColor\"/></svg>";
|
||||||
|
|
||||||
|
let activeCloseHandler = null;
|
||||||
|
|
||||||
|
function getTopDocument() {
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (!topWin || !topWin.document) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return topWin.document;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeOverlay() {
|
||||||
|
const doc = getTopDocument();
|
||||||
|
if (!doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const overlay = doc.getElementById(OVERLAY_ID);
|
||||||
|
if (overlay && overlay.parentNode) {
|
||||||
|
overlay.parentNode.removeChild(overlay);
|
||||||
|
}
|
||||||
|
if (activeCloseHandler && doc.removeEventListener) {
|
||||||
|
doc.removeEventListener("keydown", activeCloseHandler);
|
||||||
|
}
|
||||||
|
activeCloseHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getQrSize() {
|
||||||
|
const size = getConfig("paymentNativeQrSize");
|
||||||
|
if (typeof size === "number" && size > 0) {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
return 220;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderQrToCanvas(canvas, codeUrl) {
|
||||||
|
const size = getQrSize();
|
||||||
|
return QRCode.toCanvas(canvas, codeUrl, {
|
||||||
|
width: size,
|
||||||
|
margin: 2,
|
||||||
|
color: {
|
||||||
|
dark: "#000000",
|
||||||
|
light: "#ffffff",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭 PC Native 支付二维码弹层
|
||||||
|
*/
|
||||||
|
export function closePaymentNativeQrCode() {
|
||||||
|
removeOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在顶层页面展示微信 Native 扫码支付二维码
|
||||||
|
*/
|
||||||
|
export function showPaymentNativeQrCode(codeUrl) {
|
||||||
|
if (!codeUrl) {
|
||||||
|
return Promise.reject(new Error("codeUrl is required"));
|
||||||
|
}
|
||||||
|
if (getConfig("paymentNativeQrEnabled") === false) {
|
||||||
|
return Promise.resolve({ shown: false, codeUrl });
|
||||||
|
}
|
||||||
|
|
||||||
|
const doc = getTopDocument();
|
||||||
|
if (!doc || !doc.body) {
|
||||||
|
return Promise.reject(new Error("top window document is not available"));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeOverlay();
|
||||||
|
|
||||||
|
const overlayClass = getConfig("paymentNativeQrOverlayClass");
|
||||||
|
const panelClass = getConfig("paymentNativeQrPanelClass");
|
||||||
|
|
||||||
|
const overlay = doc.createElement("div");
|
||||||
|
overlay.id = OVERLAY_ID;
|
||||||
|
overlay.style.cssText = getConfig("paymentNativeQrOverlayStyle")
|
||||||
|
|| "position:fixed;left:0;top:0;right:0;bottom:0;z-index:100002;background:rgba(0,0,0,0.55);display:flex;align-items:center;justify-content:center;padding:20px;box-sizing:border-box;";
|
||||||
|
if (overlayClass) {
|
||||||
|
overlay.className = overlayClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
const panel = doc.createElement("div");
|
||||||
|
panel.style.cssText = getConfig("paymentNativeQrPanelStyle")
|
||||||
|
|| "position:relative;width:100%;max-width:320px;background:#fff;border-radius:12px;padding:24px 20px 20px;box-shadow:0 8px 28px rgba(0,0,0,0.22);text-align:center;";
|
||||||
|
if (panelClass) {
|
||||||
|
panel.className = panelClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeBtn = doc.createElement("button");
|
||||||
|
closeBtn.type = "button";
|
||||||
|
closeBtn.setAttribute("aria-label", "关闭");
|
||||||
|
closeBtn.style.cssText = getConfig("paymentNativeQrCloseButtonStyle")
|
||||||
|
|| "position:absolute;top:10px;right:10px;width:32px;height:32px;padding:0;border:0;border-radius:50%;background:rgba(0,0,0,0.06);color:#666;display:flex;align-items:center;justify-content:center;cursor:pointer;";
|
||||||
|
closeBtn.innerHTML = CLOSE_ICON_SVG;
|
||||||
|
closeBtn.onclick = (event) => {
|
||||||
|
event.preventDefault && event.preventDefault();
|
||||||
|
removeOverlay();
|
||||||
|
};
|
||||||
|
|
||||||
|
const title = doc.createElement("h3");
|
||||||
|
title.textContent = getConfig("paymentNativeQrTitle") || "微信扫码支付";
|
||||||
|
title.style.cssText = "margin:0 0 8px;font-size:18px;font-weight:600;color:#222;line-height:1.35;";
|
||||||
|
|
||||||
|
const message = doc.createElement("p");
|
||||||
|
message.textContent = getConfig("paymentNativeQrMessage") || "请使用微信扫一扫,扫描二维码完成支付";
|
||||||
|
message.style.cssText = "margin:0 0 16px;font-size:14px;color:#666;line-height:1.5;";
|
||||||
|
|
||||||
|
const qrWrap = doc.createElement("div");
|
||||||
|
qrWrap.style.cssText = "display:flex;align-items:center;justify-content:center;padding:8px;background:#fff;border:1px solid #eee;border-radius:8px;";
|
||||||
|
|
||||||
|
const canvas = doc.createElement("canvas");
|
||||||
|
qrWrap.appendChild(canvas);
|
||||||
|
|
||||||
|
const hint = doc.createElement("p");
|
||||||
|
hint.textContent = getConfig("paymentNativeQrHint") || "支付完成后请稍候,系统将自动确认结果";
|
||||||
|
hint.style.cssText = "margin:14px 0 0;font-size:12px;color:#999;line-height:1.45;";
|
||||||
|
|
||||||
|
panel.appendChild(closeBtn);
|
||||||
|
panel.appendChild(title);
|
||||||
|
panel.appendChild(message);
|
||||||
|
panel.appendChild(qrWrap);
|
||||||
|
panel.appendChild(hint);
|
||||||
|
overlay.appendChild(panel);
|
||||||
|
doc.body.appendChild(overlay);
|
||||||
|
|
||||||
|
activeCloseHandler = (event) => {
|
||||||
|
if (event && event.key === "Escape") {
|
||||||
|
removeOverlay();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
doc.addEventListener("keydown", activeCloseHandler);
|
||||||
|
|
||||||
|
overlay.onclick = (event) => {
|
||||||
|
if (event.target === overlay) {
|
||||||
|
removeOverlay();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return renderQrToCanvas(canvas, codeUrl).then(() => ({
|
||||||
|
shown: true,
|
||||||
|
codeUrl,
|
||||||
|
})).catch((err) => {
|
||||||
|
removeOverlay();
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
307
src/services/payment/oauth.js
Normal file
307
src/services/payment/oauth.js
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
import { getConfig } from "../config";
|
||||||
|
import { request } from "../../utils/request";
|
||||||
|
import { toAny } from "../../utils/toany";
|
||||||
|
import { getTopWindow } from "./env";
|
||||||
|
import { getPaymentConfig } from "./config";
|
||||||
|
|
||||||
|
const DEFAULT_STORAGE_KEY_PREFIX = "iscan_wechat_openid";
|
||||||
|
|
||||||
|
let resolvedOAuthAppId = "";
|
||||||
|
|
||||||
|
function getOAuthConfig() {
|
||||||
|
return getPaymentConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setResolvedOAuthAppId(appId) {
|
||||||
|
if (appId) {
|
||||||
|
resolvedOAuthAppId = String(appId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getResolvedOAuthAppId() {
|
||||||
|
return resolvedOAuthAppId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildStorageKey(appId) {
|
||||||
|
const cfg = getOAuthConfig();
|
||||||
|
if (cfg.storageKey) {
|
||||||
|
return cfg.storageKey;
|
||||||
|
}
|
||||||
|
const id = appId || getResolvedOAuthAppId();
|
||||||
|
if (id) {
|
||||||
|
return `${DEFAULT_STORAGE_KEY_PREFIX}_${id}`;
|
||||||
|
}
|
||||||
|
return DEFAULT_STORAGE_KEY_PREFIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSessionStorage() {
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (!topWin) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return topWin.sessionStorage;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCachedOpenid(appId) {
|
||||||
|
const storage = getSessionStorage();
|
||||||
|
if (!storage) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return storage.getItem(buildStorageKey(appId)) || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeCachedOpenid(appId, openid) {
|
||||||
|
const storage = getSessionStorage();
|
||||||
|
if (!storage || !openid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
storage.setItem(buildStorageKey(appId), openid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearCachedOpenid(appId) {
|
||||||
|
const storage = getSessionStorage();
|
||||||
|
if (!storage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = buildStorageKey(appId);
|
||||||
|
if (key) {
|
||||||
|
storage.removeItem(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function releaseWechatOAuth(appId) {
|
||||||
|
clearCachedOpenid(appId || getResolvedOAuthAppId());
|
||||||
|
if (!appId || appId === getResolvedOAuthAppId()) {
|
||||||
|
resolvedOAuthAppId = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCodeFromLocation(win) {
|
||||||
|
if (!win || !win.location) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams(win.location.search || "");
|
||||||
|
return params.get("code") || "";
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripOAuthQueryFromUrl(win) {
|
||||||
|
if (!win || !win.history || !win.location) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const url = new URL(win.location.href);
|
||||||
|
const keys = ["code", "state", "error", "error_description"];
|
||||||
|
let changed = false;
|
||||||
|
keys.forEach((key) => {
|
||||||
|
if (url.searchParams.has(key)) {
|
||||||
|
url.searchParams.delete(key);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!changed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const next = url.pathname + url.search + url.hash;
|
||||||
|
win.history.replaceState(win.history.state, "", next);
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOAuthErrorFromLocation(win) {
|
||||||
|
if (!win || !win.location) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams(win.location.search || "");
|
||||||
|
const error = params.get("error");
|
||||||
|
if (!error) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return params.get("error_description") || error;
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseOAuthResponse(res) {
|
||||||
|
const body = toAny(res && res.data, {});
|
||||||
|
if (!body) {
|
||||||
|
throw new Error("wechat oauth response is empty");
|
||||||
|
}
|
||||||
|
if (body.code !== undefined && body.code !== 0) {
|
||||||
|
throw new Error(body.msg || body.message || "wechat oauth failed");
|
||||||
|
}
|
||||||
|
const data = body.data != null ? body.data : body;
|
||||||
|
const appId = data && data.appId;
|
||||||
|
const openid = data && data.openid;
|
||||||
|
if (!appId) {
|
||||||
|
throw new Error("wechat oauth appId is empty");
|
||||||
|
}
|
||||||
|
if (!openid) {
|
||||||
|
throw new Error("wechat oauth openid is empty");
|
||||||
|
}
|
||||||
|
setResolvedOAuthAppId(appId);
|
||||||
|
return {
|
||||||
|
appId: String(appId),
|
||||||
|
openid: String(openid),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseAuthorizeUrlResponse(res) {
|
||||||
|
const body = toAny(res && res.data, {});
|
||||||
|
if (!body) {
|
||||||
|
throw new Error("wechat oauth authorize url response is empty");
|
||||||
|
}
|
||||||
|
if (body.code !== undefined && body.code !== 0) {
|
||||||
|
throw new Error(body.msg || body.message || "wechat oauth authorize url failed");
|
||||||
|
}
|
||||||
|
const data = body.data != null ? body.data : body;
|
||||||
|
const appId = data && data.appId;
|
||||||
|
const authorizeUrl = data && (data.authorizeUrl || data.authorize_url);
|
||||||
|
if (!appId) {
|
||||||
|
throw new Error("wechat oauth authorizeUrl appId is empty");
|
||||||
|
}
|
||||||
|
if (!authorizeUrl) {
|
||||||
|
throw new Error("wechat oauth authorizeUrl is empty");
|
||||||
|
}
|
||||||
|
setResolvedOAuthAppId(appId);
|
||||||
|
return {
|
||||||
|
appId: String(appId),
|
||||||
|
authorizeUrl: String(authorizeUrl),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildDefaultRedirectUri(win) {
|
||||||
|
if (!win || !win.location) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const url = new URL(win.location.href);
|
||||||
|
url.searchParams.delete("code");
|
||||||
|
url.searchParams.delete("state");
|
||||||
|
url.searchParams.delete("error");
|
||||||
|
url.searchParams.delete("error_description");
|
||||||
|
url.hash = "";
|
||||||
|
return url.href.split("#")[0];
|
||||||
|
} catch (e) {
|
||||||
|
return win.location.href.split("#")[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveRedirectUri(options, win) {
|
||||||
|
const opts = toAny(options, {});
|
||||||
|
const cfg = getOAuthConfig();
|
||||||
|
if (opts.redirectUri) {
|
||||||
|
return String(opts.redirectUri).split("#")[0];
|
||||||
|
}
|
||||||
|
if (cfg.redirectUri) {
|
||||||
|
return String(cfg.redirectUri).split("#")[0];
|
||||||
|
}
|
||||||
|
return buildDefaultRedirectUri(win);
|
||||||
|
}
|
||||||
|
|
||||||
|
function exchangeCodeForOpenid(code) {
|
||||||
|
const cfg = getOAuthConfig();
|
||||||
|
const apiUrl = cfg.oauthApiUrl;
|
||||||
|
if (!apiUrl) {
|
||||||
|
return Promise.reject(new Error("initWechatPayment.oauthApiUrl is required"));
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: apiUrl,
|
||||||
|
method: "POST",
|
||||||
|
json: true,
|
||||||
|
data: { code },
|
||||||
|
}).then(parseOAuthResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fetchAuthorizeInfo(redirectUri) {
|
||||||
|
const cfg = getOAuthConfig();
|
||||||
|
const apiUrl = cfg.oauthAuthorizeUrlApiUrl;
|
||||||
|
if (!apiUrl) {
|
||||||
|
return Promise.reject(new Error("initWechatPayment.oauthAuthorizeUrlApiUrl is required"));
|
||||||
|
}
|
||||||
|
if (!redirectUri) {
|
||||||
|
return Promise.reject(new Error("redirectUri is required for wechat oauth authorize url"));
|
||||||
|
}
|
||||||
|
return request({
|
||||||
|
url: apiUrl,
|
||||||
|
method: "POST",
|
||||||
|
json: true,
|
||||||
|
data: { redirectUri },
|
||||||
|
}).then(parseAuthorizeUrlResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirectToAuthorize(authorizeUrl) {
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (!topWin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
topWin.location.href = authorizeUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rejectWechatOAuth(topWin, appId, error) {
|
||||||
|
releaseWechatOAuth(appId);
|
||||||
|
if (topWin) {
|
||||||
|
stripOAuthQueryFromUrl(topWin);
|
||||||
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付 JSAPI:先拉取授权信息获取 appId,再查缓存 / 换 code / 跳转授权。
|
||||||
|
* 需要跳转授权时返回 null;失败时释放 openid 缓存并 reject。
|
||||||
|
*/
|
||||||
|
export function ensureWechatOpenid(options) {
|
||||||
|
const opts = toAny(options, {});
|
||||||
|
const topWin = getTopWindow();
|
||||||
|
if (!topWin) {
|
||||||
|
return Promise.reject(new Error("window is not available"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const oauthError = getOAuthErrorFromLocation(topWin);
|
||||||
|
if (oauthError) {
|
||||||
|
return rejectWechatOAuth(topWin, getResolvedOAuthAppId(), new Error(`wechat oauth failed: ${oauthError}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirectUri = resolveRedirectUri(opts, topWin);
|
||||||
|
const code = getCodeFromLocation(topWin);
|
||||||
|
|
||||||
|
return fetchAuthorizeInfo(redirectUri).then((authInfo) => {
|
||||||
|
const appId = authInfo.appId;
|
||||||
|
|
||||||
|
if (!opts.force) {
|
||||||
|
const cached = readCachedOpenid(appId);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code) {
|
||||||
|
return exchangeCodeForOpenid(code).then((result) => {
|
||||||
|
writeCachedOpenid(result.appId, result.openid);
|
||||||
|
stripOAuthQueryFromUrl(topWin);
|
||||||
|
return result.openid;
|
||||||
|
}).catch((err) => rejectWechatOAuth(topWin, appId, err));
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectToAuthorize(authInfo.authorizeUrl);
|
||||||
|
return null;
|
||||||
|
}).catch((err) => rejectWechatOAuth(topWin, getResolvedOAuthAppId(), err));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clearWechatOpenidCache(appId) {
|
||||||
|
clearCachedOpenid(appId || getResolvedOAuthAppId());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCachedWechatOpenid(appId) {
|
||||||
|
return readCachedOpenid(appId || getResolvedOAuthAppId());
|
||||||
|
}
|
||||||
@@ -401,16 +401,11 @@ function invokeGetUserMedia(constraints) {
|
|||||||
return Promise.reject(new Error("getUserMedia is not supported"));
|
return Promise.reject(new Error("getUserMedia is not supported"));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWebScanCameraProbeTimeout() {
|
|
||||||
const timeout = getConfig("webScanCameraProbeTimeout");
|
|
||||||
return typeof timeout === "number" && timeout > 0 ? timeout : 3000;
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveWebCameraConfigOverride() {
|
function resolveWebCameraConfigOverride() {
|
||||||
if (getConfig("webScanCameraEnabled") === false || getConfig("webScanCameraInWechat") === false) {
|
if (getConfig("webScanCameraEnabled") === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getConfig("webScanCameraEnabled") === true || getConfig("webScanCameraInWechat") === true) {
|
if (getConfig("webScanCameraEnabled") === true) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -424,19 +419,6 @@ export function shouldSkipWebCameraProbe() {
|
|||||||
return !!isSupportWxScan();
|
return !!isSupportWxScan();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步判断是否具备 Web 摄像头扫码条件(不申请权限)。
|
|
||||||
* @deprecated 请用 canUseWebCameraScan;保留兼容,不再调用 getUserMedia
|
|
||||||
*/
|
|
||||||
export function probeWebCameraScan() {
|
|
||||||
if (shouldSkipWebCameraProbe()) {
|
|
||||||
return Promise.resolve(false);
|
|
||||||
}
|
|
||||||
const supported = canUseWebCameraScan();
|
|
||||||
printDebug("web camera capability (sync):", supported);
|
|
||||||
return Promise.resolve(supported);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resetWebCameraSupportProbe() {
|
export function resetWebCameraSupportProbe() {
|
||||||
webCameraSupportProbed = null;
|
webCameraSupportProbed = null;
|
||||||
webCameraPermissionGrantedCache = null;
|
webCameraPermissionGrantedCache = null;
|
||||||
|
|||||||
162
types/index.d.ts
vendored
162
types/index.d.ts
vendored
@@ -53,14 +53,6 @@ interface ScanConfigOptions {
|
|||||||
* 是否允许 H5 摄像头扫码:true 强制开启(仍需有媒体 API),false 强制关闭
|
* 是否允许 H5 摄像头扫码:true 强制开启(仍需有媒体 API),false 强制关闭
|
||||||
*/
|
*/
|
||||||
webScanCameraEnabled?: boolean,
|
webScanCameraEnabled?: boolean,
|
||||||
/**
|
|
||||||
* @deprecated 请用 webScanCameraEnabled;保留兼容
|
|
||||||
*/
|
|
||||||
webScanCameraInWechat?: boolean,
|
|
||||||
/**
|
|
||||||
* @deprecated 摄像头权限已后置到 startScan,请用 webScanVideoAccessTimeout
|
|
||||||
*/
|
|
||||||
webScanCameraProbeTimeout?: number,
|
|
||||||
/**
|
/**
|
||||||
* startScan 走 Web 摄像头前是否展示权限说明弹窗,默认 true
|
* startScan 走 Web 摄像头前是否展示权限说明弹窗,默认 true
|
||||||
*/
|
*/
|
||||||
@@ -196,6 +188,68 @@ interface ScanConfigOptions {
|
|||||||
* 扫码成功是否播放提示音,默认启用;任意识别模式匹配成功时生效
|
* 扫码成功是否播放提示音,默认启用;任意识别模式匹配成功时生效
|
||||||
*/
|
*/
|
||||||
scanBeepEnabled?: boolean,
|
scanBeepEnabled?: boolean,
|
||||||
|
/**
|
||||||
|
* PC 微信 Native 扫码支付是否展示内置二维码弹层,默认 true
|
||||||
|
*/
|
||||||
|
paymentNativeQrEnabled?: boolean,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层标题
|
||||||
|
*/
|
||||||
|
paymentNativeQrTitle?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层说明文案
|
||||||
|
*/
|
||||||
|
paymentNativeQrMessage?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码底部提示
|
||||||
|
*/
|
||||||
|
paymentNativeQrHint?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码边长(像素),默认 220
|
||||||
|
*/
|
||||||
|
paymentNativeQrSize?: number,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层遮罩样式
|
||||||
|
*/
|
||||||
|
paymentNativeQrOverlayStyle?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层面板样式
|
||||||
|
*/
|
||||||
|
paymentNativeQrPanelStyle?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码关闭按钮样式
|
||||||
|
*/
|
||||||
|
paymentNativeQrCloseButtonStyle?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层遮罩 class
|
||||||
|
*/
|
||||||
|
paymentNativeQrOverlayClass?: string,
|
||||||
|
/**
|
||||||
|
* Native 支付二维码弹层面板 class
|
||||||
|
*/
|
||||||
|
paymentNativeQrPanelClass?: string,
|
||||||
|
/**
|
||||||
|
* 微信支付 OAuth 配置(paymentType 为 wechat 且微信内 JSAPI 时由 requestPayment 自动处理)
|
||||||
|
*/
|
||||||
|
initWechatPayment?: {
|
||||||
|
/**
|
||||||
|
* 用 code 换 openid,对应 api.biz.wechat.oauth
|
||||||
|
*/
|
||||||
|
oauthApiUrl?: string,
|
||||||
|
/**
|
||||||
|
* 获取 OAuth 授权信息(含 appId、authorizeUrl),对应 api.biz.wechat.oauthAuthorizeUrl
|
||||||
|
*/
|
||||||
|
oauthAuthorizeUrlApiUrl?: string,
|
||||||
|
/**
|
||||||
|
* openid 缓存 key,默认 iscan_wechat_openid_${appId}(appId 来自授权接口响应)
|
||||||
|
*/
|
||||||
|
storageKey?: string,
|
||||||
|
/**
|
||||||
|
* OAuth 授权回跳完整 URL(redirectUri),须与当前页域名一致且已在公众号登记;
|
||||||
|
* 未配置时默认使用当前页 location.href(不含 hash)
|
||||||
|
*/
|
||||||
|
redirectUri?: string,
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 微信JSSDK配置,微信环境才会生效,配置后会自动初始化微信JSSDK
|
* 微信JSSDK配置,微信环境才会生效,配置后会自动初始化微信JSSDK
|
||||||
*/
|
*/
|
||||||
@@ -319,6 +373,79 @@ interface ScanErrorListenerInfo {
|
|||||||
*/
|
*/
|
||||||
type ScanStatusCallback = (status: ScanStatus) => any;
|
type ScanStatusCallback = (status: ScanStatus) => any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付渠道
|
||||||
|
*/
|
||||||
|
type PaymentType = 'wechat' | 'alipay';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSAPI 收银台交互结果(仅表示用户在收银台的操作,非支付到账结果)
|
||||||
|
*/
|
||||||
|
type PaymentCashierResult = 'ok' | 'cancel' | 'fail';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付场景
|
||||||
|
*/
|
||||||
|
type PayScene = 'jsapi' | 'h5' | 'native';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDK 传给业务支付函数的参数(OAuth、环境判断由 SDK 自动完成)
|
||||||
|
*/
|
||||||
|
interface PaymentPrepareParams {
|
||||||
|
/** 微信 JSAPI 场景下的 openid,其他场景为空字符串 */
|
||||||
|
openid: string;
|
||||||
|
/** 当前环境对应的微信支付场景 */
|
||||||
|
payScene: PayScene;
|
||||||
|
/** navigator.userAgent */
|
||||||
|
userAgent: string;
|
||||||
|
/** 用户 IP,默认空字符串 */
|
||||||
|
clientIp: string;
|
||||||
|
/** 支付完成回跳地址 */
|
||||||
|
returnUrl: string;
|
||||||
|
/** 支付渠道 */
|
||||||
|
paymentType: PaymentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务支付函数:调用自己的支付接口,返回 paymentFormData
|
||||||
|
*/
|
||||||
|
type PaymentFormDataProvider = (
|
||||||
|
params: PaymentPrepareParams
|
||||||
|
) => string | Record<string, any> | Promise<string | Record<string, any>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDK 发起支付后的返回(不代表支付成功,业务须自行查单)
|
||||||
|
*/
|
||||||
|
interface PaymentInvokeResult {
|
||||||
|
payType?: 'jsapi' | 'h5' | 'native' | 'alipay';
|
||||||
|
/** SDK 是否已发起支付流程 */
|
||||||
|
invoked: boolean;
|
||||||
|
/** 微信 OAuth 授权跳转中(页面将刷新,业务函数尚未执行) */
|
||||||
|
oauthRedirecting?: boolean;
|
||||||
|
/** 支付未发起(含微信 OAuth 失败) */
|
||||||
|
failed?: boolean;
|
||||||
|
/** 微信 OAuth / openid 获取失败 */
|
||||||
|
oauthFailed?: boolean;
|
||||||
|
/** OAuth 或调起失败时的错误信息 */
|
||||||
|
error?: string;
|
||||||
|
/** H5 / 支付宝是否已跳转 */
|
||||||
|
redirected?: boolean;
|
||||||
|
/** Native 场景是否展示了二维码弹层 */
|
||||||
|
qrShown?: boolean;
|
||||||
|
/** 微信 JSAPI 收银台交互结果(非支付到账结果) */
|
||||||
|
cashierResult?: PaymentCashierResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付请求选项
|
||||||
|
*/
|
||||||
|
interface RequestPaymentOptions {
|
||||||
|
/** 支付完成回跳地址,未传时使用当前页 URL */
|
||||||
|
returnUrl?: string;
|
||||||
|
/** OAuth 授权回跳完整 URL(redirectUri),覆盖 initWechatPayment.redirectUri */
|
||||||
|
redirectUri?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/** IScan */
|
/** IScan */
|
||||||
interface IScan {
|
interface IScan {
|
||||||
/**
|
/**
|
||||||
@@ -377,12 +504,29 @@ interface IScan {
|
|||||||
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
|
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
|
||||||
*/
|
*/
|
||||||
scanImage(key?: string): void;
|
scanImage(key?: string): void;
|
||||||
/** 由业务/原生传入已选图片 File 识别(WebView input.files 异常时使用) */
|
/**
|
||||||
|
* 由业务/原生传入已选图片 File 识别(WebView input.files 异常时使用)
|
||||||
|
* @param file 已选图片 File
|
||||||
|
* @param key 可选,指定后结果仅分发给同 key 的 onScanListener
|
||||||
|
*/
|
||||||
scanImageFromFile(file: File | Blob, key?: string): void;
|
scanImageFromFile(file: File | Blob, key?: string): void;
|
||||||
/**
|
/**
|
||||||
* 清除全部监听
|
* 清除全部监听
|
||||||
*/
|
*/
|
||||||
clear(): void;
|
clear(): void;
|
||||||
|
/**
|
||||||
|
* 发起支付:按 paymentType 决定是否走微信 OAuth,再将参数传给业务函数获取 paymentFormData 并调起支付。
|
||||||
|
* 不代表支付成功,业务须自行查单。
|
||||||
|
*/
|
||||||
|
requestPayment(
|
||||||
|
paymentType: PaymentType,
|
||||||
|
fetchPaymentFormData: PaymentFormDataProvider,
|
||||||
|
options?: RequestPaymentOptions
|
||||||
|
): Promise<PaymentInvokeResult>;
|
||||||
|
/**
|
||||||
|
* 关闭 SDK 管理的支付相关 UI(如 PC Native 二维码弹层)
|
||||||
|
*/
|
||||||
|
closePaymentDialog(): void;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user