@vobs/payment 0.3.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +182 -0
  3. package/dist/alipay/client.cjs +112 -0
  4. package/dist/alipay/client.cjs.map +1 -0
  5. package/dist/alipay/client.d.cts +36 -0
  6. package/dist/alipay/client.d.ts +36 -0
  7. package/dist/alipay/client.js +110 -0
  8. package/dist/alipay/client.js.map +1 -0
  9. package/dist/alipay/config.cjs +67 -0
  10. package/dist/alipay/config.cjs.map +1 -0
  11. package/dist/alipay/config.d.cts +30 -0
  12. package/dist/alipay/config.d.ts +30 -0
  13. package/dist/alipay/config.js +65 -0
  14. package/dist/alipay/config.js.map +1 -0
  15. package/dist/alipay/index.cjs +592 -0
  16. package/dist/alipay/index.cjs.map +1 -0
  17. package/dist/alipay/index.d.cts +12 -0
  18. package/dist/alipay/index.d.ts +12 -0
  19. package/dist/alipay/index.js +580 -0
  20. package/dist/alipay/index.js.map +1 -0
  21. package/dist/alipay/notify.cjs +70 -0
  22. package/dist/alipay/notify.cjs.map +1 -0
  23. package/dist/alipay/notify.d.cts +52 -0
  24. package/dist/alipay/notify.d.ts +52 -0
  25. package/dist/alipay/notify.js +68 -0
  26. package/dist/alipay/notify.js.map +1 -0
  27. package/dist/alipay/payment.cjs +49 -0
  28. package/dist/alipay/payment.cjs.map +1 -0
  29. package/dist/alipay/payment.d.cts +24 -0
  30. package/dist/alipay/payment.d.ts +24 -0
  31. package/dist/alipay/payment.js +47 -0
  32. package/dist/alipay/payment.js.map +1 -0
  33. package/dist/alipay/plugin.cjs +300 -0
  34. package/dist/alipay/plugin.cjs.map +1 -0
  35. package/dist/alipay/plugin.d.cts +43 -0
  36. package/dist/alipay/plugin.d.ts +43 -0
  37. package/dist/alipay/plugin.js +296 -0
  38. package/dist/alipay/plugin.js.map +1 -0
  39. package/dist/alipay/query.cjs +80 -0
  40. package/dist/alipay/query.cjs.map +1 -0
  41. package/dist/alipay/query.d.cts +26 -0
  42. package/dist/alipay/query.d.ts +26 -0
  43. package/dist/alipay/query.js +78 -0
  44. package/dist/alipay/query.js.map +1 -0
  45. package/dist/alipay/refund.cjs +104 -0
  46. package/dist/alipay/refund.cjs.map +1 -0
  47. package/dist/alipay/refund.d.cts +32 -0
  48. package/dist/alipay/refund.d.ts +32 -0
  49. package/dist/alipay/refund.js +102 -0
  50. package/dist/alipay/refund.js.map +1 -0
  51. package/dist/alipay/response.cjs +38 -0
  52. package/dist/alipay/response.cjs.map +1 -0
  53. package/dist/alipay/response.d.cts +19 -0
  54. package/dist/alipay/response.d.ts +19 -0
  55. package/dist/alipay/response.js +35 -0
  56. package/dist/alipay/response.js.map +1 -0
  57. package/dist/alipay/types.cjs +4 -0
  58. package/dist/alipay/types.cjs.map +1 -0
  59. package/dist/alipay/types.d.cts +242 -0
  60. package/dist/alipay/types.d.ts +242 -0
  61. package/dist/alipay/types.js +3 -0
  62. package/dist/alipay/types.js.map +1 -0
  63. package/dist/alipay/wap.cjs +50 -0
  64. package/dist/alipay/wap.cjs.map +1 -0
  65. package/dist/alipay/wap.d.cts +24 -0
  66. package/dist/alipay/wap.d.ts +24 -0
  67. package/dist/alipay/wap.js +48 -0
  68. package/dist/alipay/wap.js.map +1 -0
  69. package/dist/index-B1aUR7Vt.d.ts +49 -0
  70. package/dist/index-B8pzZxGq.d.cts +44 -0
  71. package/dist/index-BWnIrwRi.d.ts +44 -0
  72. package/dist/index-Dyrkl86r.d.cts +49 -0
  73. package/dist/index.cjs +1071 -0
  74. package/dist/index.cjs.map +1 -0
  75. package/dist/index.d.cts +23 -0
  76. package/dist/index.d.ts +23 -37
  77. package/dist/index.js +1052 -37
  78. package/dist/index.js.map +1 -0
  79. package/dist/wechat/client.cjs +119 -0
  80. package/dist/wechat/client.cjs.map +1 -0
  81. package/dist/wechat/client.d.cts +39 -0
  82. package/dist/wechat/client.d.ts +39 -0
  83. package/dist/wechat/client.js +117 -0
  84. package/dist/wechat/client.js.map +1 -0
  85. package/dist/wechat/config.cjs +76 -0
  86. package/dist/wechat/config.cjs.map +1 -0
  87. package/dist/wechat/config.d.cts +29 -0
  88. package/dist/wechat/config.d.ts +29 -0
  89. package/dist/wechat/config.js +74 -0
  90. package/dist/wechat/config.js.map +1 -0
  91. package/dist/wechat/index.cjs +612 -0
  92. package/dist/wechat/index.cjs.map +1 -0
  93. package/dist/wechat/index.d.cts +10 -0
  94. package/dist/wechat/index.d.ts +10 -0
  95. package/dist/wechat/index.js +602 -0
  96. package/dist/wechat/index.js.map +1 -0
  97. package/dist/wechat/notify.cjs +73 -0
  98. package/dist/wechat/notify.cjs.map +1 -0
  99. package/dist/wechat/notify.d.cts +53 -0
  100. package/dist/wechat/notify.d.ts +53 -0
  101. package/dist/wechat/notify.js +71 -0
  102. package/dist/wechat/notify.js.map +1 -0
  103. package/dist/wechat/payment.cjs +186 -0
  104. package/dist/wechat/payment.cjs.map +1 -0
  105. package/dist/wechat/payment.d.cts +50 -0
  106. package/dist/wechat/payment.d.ts +50 -0
  107. package/dist/wechat/payment.js +184 -0
  108. package/dist/wechat/payment.js.map +1 -0
  109. package/dist/wechat/plugin.cjs +305 -0
  110. package/dist/wechat/plugin.cjs.map +1 -0
  111. package/dist/wechat/plugin.d.cts +40 -0
  112. package/dist/wechat/plugin.d.ts +40 -0
  113. package/dist/wechat/plugin.js +301 -0
  114. package/dist/wechat/plugin.js.map +1 -0
  115. package/dist/wechat/refund.cjs +112 -0
  116. package/dist/wechat/refund.cjs.map +1 -0
  117. package/dist/wechat/refund.d.cts +26 -0
  118. package/dist/wechat/refund.d.ts +26 -0
  119. package/dist/wechat/refund.js +110 -0
  120. package/dist/wechat/refund.js.map +1 -0
  121. package/dist/wechat/response.cjs +50 -0
  122. package/dist/wechat/response.cjs.map +1 -0
  123. package/dist/wechat/response.d.cts +20 -0
  124. package/dist/wechat/response.d.ts +20 -0
  125. package/dist/wechat/response.js +46 -0
  126. package/dist/wechat/response.js.map +1 -0
  127. package/dist/wechat/types.cjs +4 -0
  128. package/dist/wechat/types.cjs.map +1 -0
  129. package/dist/wechat/types.d.cts +200 -0
  130. package/dist/wechat/types.d.ts +200 -0
  131. package/dist/wechat/types.js +3 -0
  132. package/dist/wechat/types.js.map +1 -0
  133. package/package.json +37 -28
  134. package/src/alipay/alipay.test.ts +231 -0
  135. package/src/alipay/client.ts +67 -0
  136. package/src/alipay/config.ts +72 -0
  137. package/src/alipay/index.ts +32 -0
  138. package/src/alipay/notify.ts +92 -0
  139. package/src/alipay/payment.ts +60 -0
  140. package/src/alipay/plugin.ts +64 -0
  141. package/src/alipay/query.ts +52 -0
  142. package/src/alipay/refund.ts +85 -0
  143. package/src/alipay/response.ts +40 -0
  144. package/src/alipay/types.ts +271 -0
  145. package/src/alipay/wap.ts +55 -0
  146. package/src/index.ts +78 -0
  147. package/src/wechat/client.ts +68 -0
  148. package/src/wechat/config.ts +81 -0
  149. package/src/wechat/index.ts +30 -0
  150. package/src/wechat/notify.ts +93 -0
  151. package/src/wechat/payment.ts +177 -0
  152. package/src/wechat/plugin.ts +59 -0
  153. package/src/wechat/refund.ts +80 -0
  154. package/src/wechat/response.ts +54 -0
  155. package/src/wechat/types.ts +223 -0
  156. package/src/wechat/wechat.test.ts +393 -0
  157. package/dist/alipay-official.d.ts +0 -34
  158. package/dist/alipay-official.js +0 -206
  159. package/dist/handlers.d.ts +0 -45
  160. package/dist/handlers.js +0 -105
  161. package/dist/jeepay.d.ts +0 -39
  162. package/dist/jeepay.js +0 -206
  163. package/dist/lakala.d.ts +0 -41
  164. package/dist/lakala.js +0 -243
  165. package/dist/manager.d.ts +0 -67
  166. package/dist/manager.js +0 -538
  167. package/dist/mock-driver.d.ts +0 -22
  168. package/dist/mock-driver.js +0 -59
  169. package/dist/state-machine.d.ts +0 -41
  170. package/dist/state-machine.js +0 -60
  171. package/dist/store.d.ts +0 -33
  172. package/dist/store.js +0 -76
  173. package/dist/types.d.ts +0 -168
  174. package/dist/types.js +0 -11
  175. package/dist/verify.d.ts +0 -34
  176. package/dist/verify.js +0 -55
  177. package/dist/wechat-official.d.ts +0 -40
  178. package/dist/wechat-official.js +0 -208
@@ -0,0 +1,85 @@
1
+ import type { AlipayClient } from './client'
2
+ import { unwrapResponse } from './response'
3
+ import type {
4
+ AlipayRefundParams,
5
+ AlipayRefundResult,
6
+ AlipayRefundQueryParams,
7
+ AlipayRefundQueryResult,
8
+ AlipayCloseParams,
9
+ AlipayCloseResult
10
+ } from './types'
11
+
12
+ /**
13
+ * 退款与交易关闭
14
+ *
15
+ * 包含退款、退款查询、交易关闭的完整退款生命周期管理。
16
+ */
17
+ export function createRefund(client: AlipayClient) {
18
+ return {
19
+ /**
20
+ * 交易退款 (alipay.trade.refund)
21
+ * 交易发生后 12 个月内可退款,退款资金原路返回。
22
+ * @throws {AlipayApiError} 业务失败时抛出
23
+ */
24
+ async refund(params: AlipayRefundParams): Promise<AlipayRefundResult> {
25
+ const alipayResponse = unwrapResponse(
26
+ await client.sdk.exec('alipay.trade.refund', {
27
+ bizContent: params
28
+ }),
29
+ 'alipay.trade.refund'
30
+ )
31
+
32
+ return {
33
+ tradeNo: alipayResponse.trade_no,
34
+ outTradeNo: alipayResponse.out_trade_no,
35
+ buyerLogonId: alipayResponse.buyer_logon_id,
36
+ refundAmount: alipayResponse.refund_fee,
37
+ fundChange: alipayResponse.fund_change ?? 'N',
38
+ gmtRefundPay: alipayResponse.gmt_refund_pay ?? '',
39
+ refundDetailItemList: alipayResponse.refund_detail_item_list ?? null
40
+ }
41
+ },
42
+
43
+ /**
44
+ * 退款查询 (alipay.trade.fastpay.refund.query)
45
+ * 查询退款状态,确认退款是否成功。
46
+ * @throws {AlipayApiError} 业务失败时抛出
47
+ */
48
+ async queryRefund(params: AlipayRefundQueryParams): Promise<AlipayRefundQueryResult> {
49
+ const alipayResponse = unwrapResponse(
50
+ await client.sdk.exec('alipay.trade.fastpay.refund.query', {
51
+ bizContent: params
52
+ }),
53
+ 'alipay.trade.fastpay.refund.query'
54
+ )
55
+
56
+ return {
57
+ tradeNo: alipayResponse.trade_no,
58
+ outTradeNo: alipayResponse.out_trade_no,
59
+ refundAmount: alipayResponse.refund_amount,
60
+ refundStatus: alipayResponse.refund_status,
61
+ outRequestNo: alipayResponse.out_request_no,
62
+ refundReason: alipayResponse.refund_reason ?? ''
63
+ }
64
+ },
65
+
66
+ /**
67
+ * 关闭交易 (alipay.trade.close)
68
+ * 关闭未支付的订单。
69
+ * @throws {AlipayApiError} 业务失败时抛出
70
+ */
71
+ async close(params: AlipayCloseParams): Promise<AlipayCloseResult> {
72
+ const alipayResponse = unwrapResponse(
73
+ await client.sdk.exec('alipay.trade.close', {
74
+ bizContent: params
75
+ }),
76
+ 'alipay.trade.close'
77
+ )
78
+
79
+ return {
80
+ tradeNo: alipayResponse.trade_no,
81
+ outTradeNo: alipayResponse.out_trade_no
82
+ }
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * 支付宝开放接口响应解包与业务错误检查。
3
+ *
4
+ * 网关应答(HTTP 200)不代表业务成功:业务失败时响应体内
5
+ * code != '10000' 并携带 sub_code/sub_msg,必须显式检查,
6
+ * 否则会把失败结果当成功映射(字段全部 undefined)。
7
+ */
8
+ export class AlipayApiError extends Error {
9
+ readonly code: string
10
+ readonly subCode?: string
11
+ readonly subMsg?: string
12
+
13
+ constructor(apiName: string, code: string, subCode: string | undefined, subMsg: string | undefined, msg: string | undefined) {
14
+ super(`支付宝接口 ${apiName} 调用失败: ${subMsg ?? msg ?? '未知错误'} (code=${code}${subCode ? `, sub_code=${subCode}` : ''})`)
15
+ this.name = 'AlipayApiError'
16
+ this.code = code
17
+ this.subCode = subCode
18
+ this.subMsg = subMsg
19
+ }
20
+ }
21
+
22
+ /** alipay.trade.page.pay -> alipay_trade_page_pay_response */
23
+ function toResponseKey(apiName: string): string {
24
+ return `${apiName.replace(/\./g, '_')}_response`
25
+ }
26
+
27
+ /**
28
+ * 从网关应答中取出业务响应体,code !== '10000' 时抛出 AlipayApiError。
29
+ */
30
+ export function unwrapResponse(raw: unknown, apiName: string): Record<string, any> {
31
+ const outer = raw as Record<string, any> | null | undefined
32
+ const body = (outer && outer[toResponseKey(apiName)]) ?? outer
33
+ if (!body || typeof body !== 'object') {
34
+ throw new AlipayApiError(apiName, 'INVALID_RESPONSE', undefined, undefined, '响应体格式异常')
35
+ }
36
+ if (body.code !== '10000') {
37
+ throw new AlipayApiError(apiName, body.code, body.sub_code, body.sub_msg, body.msg)
38
+ }
39
+ return body
40
+ }
@@ -0,0 +1,271 @@
1
+ import type { AlipaySdkConfig, AlipaySdkSignType } from 'alipay-sdk'
2
+
3
+ // ---- 重新导出 alipay-sdk 类型 ----
4
+ export type { AlipaySdkConfig, AlipaySdkSignType }
5
+
6
+ // ---- 电脑网站支付 (alipay.trade.page.pay) ----
7
+ export interface AlipayPagePayParams {
8
+ /** 商户订单号,需保证唯一 */
9
+ outTradeNo: string
10
+ /** 订单总金额,单位元,精确到两位小数 */
11
+ totalAmount: string
12
+ /** 订单标题 */
13
+ subject: string
14
+ /** 产品代码,电脑网站支付固定为 FAST_INSTANT_TRADE_PAY */
15
+ productCode?: string
16
+ /** 订单描述 */
17
+ body?: string
18
+ /** 绝对超时时间,格式 yyyy-MM-dd HH:mm:ss */
19
+ timeExpire?: string
20
+ /** 订单相对超时时间,范围 1m~15d */
21
+ timeoutExpress?: string
22
+ /** 商品主类型:0-虚拟,1-实物 */
23
+ goodsType?: '0' | '1'
24
+ /** 公用回传参数,异步通知时原样返回 */
25
+ passbackParams?: string
26
+ /** 支付完成后同步跳转地址 */
27
+ returnUrl?: string
28
+ /** 异步通知地址 */
29
+ notifyUrl?: string
30
+ /** 扩展信息 */
31
+ extendParams?: Record<string, string>
32
+ /** 商户门店编号 */
33
+ storeId?: string
34
+ /** 是否发起实名校验 */
35
+ qrPayMode?: string
36
+ /** 扫码支付模式 */
37
+ qrcodeWidth?: string
38
+ }
39
+
40
+ export interface AlipayPagePayResult {
41
+ /** 支付宝返回的 HTML 表单字符串 */
42
+ formHtml: string
43
+ }
44
+
45
+ // ---- 手机网站支付 (alipay.trade.wap.pay) ----
46
+ export interface AlipayWapPayParams {
47
+ /** 商户订单号,需保证唯一 */
48
+ outTradeNo: string
49
+ /** 订单总金额,单位元,精确到两位小数 */
50
+ totalAmount: string
51
+ /** 订单标题 */
52
+ subject: string
53
+ /** 产品代码,手机网站支付固定为 QUICK_WAP_WAY */
54
+ productCode?: string
55
+ /** 订单描述 */
56
+ body?: string
57
+ /** 绝对超时时间,格式 yyyy-MM-dd HH:mm:ss */
58
+ timeExpire?: string
59
+ /** 订单相对超时时间,范围 1m~15d */
60
+ timeoutExpress?: string
61
+ /** 公用回传参数,异步通知时原样返回 */
62
+ passbackParams?: string
63
+ /** 用户付款中途退出后返回的商户页面地址 */
64
+ quitUrl?: string
65
+ /** 支付完成后同步跳转地址 */
66
+ returnUrl?: string
67
+ /** 异步通知地址 */
68
+ notifyUrl?: string
69
+ }
70
+
71
+ export interface AlipayWapPayResult {
72
+ /** 支付宝返回的 HTML 表单字符串 */
73
+ formHtml: string
74
+ }
75
+
76
+ // ---- 交易查询 (alipay.trade.query) ----
77
+ export interface AlipayQueryParams {
78
+ outTradeNo?: string
79
+ tradeNo?: string
80
+ }
81
+
82
+ export interface AlipayQueryResult {
83
+ /** 支付宝交易号 */
84
+ tradeNo: string
85
+ /** 商户订单号 */
86
+ outTradeNo: string
87
+ /** 买家支付宝账号 */
88
+ buyerLogonId: string
89
+ /** 交易状态 */
90
+ tradeStatus: TradeStatus
91
+ /** 交易的订单金额 */
92
+ totalAmount: string
93
+ /** 实收金额 */
94
+ receiptAmount: string
95
+ /** 买家实付金额 */
96
+ buyerPayAmount: string
97
+ /** 交易创建时间 */
98
+ sendPayDate: string
99
+ /** 交易付款时间 */
100
+ gmtPayment: string | null
101
+ /** 交易关闭时间 */
102
+ gmtClose: string | null
103
+ /** 退款金额 */
104
+ refundAmount: string
105
+ /** 商品描述 */
106
+ subject: string
107
+ /** 商户传入的回传参数 */
108
+ passbackParams: string | null
109
+ /** 本次交易支付工具 */
110
+ fundChannel: string | null
111
+ }
112
+
113
+ // ---- 交易退款 (alipay.trade.refund) ----
114
+ export interface AlipayRefundParams {
115
+ outTradeNo?: string
116
+ tradeNo?: string
117
+ refundAmount: string
118
+ refundReason?: string
119
+ outRequestNo?: string
120
+ refundCurrency?: string
121
+ }
122
+
123
+ export interface AlipayRefundResult {
124
+ /** 支付宝交易号 */
125
+ tradeNo: string
126
+ /** 商户订单号 */
127
+ outTradeNo: string
128
+ /** 买家支付宝账号 */
129
+ buyerLogonId: string
130
+ /** 本次退款请求金额 */
131
+ refundAmount: string
132
+ /** 资金变动明细 */
133
+ fundChange: string
134
+ /** 退款时间 */
135
+ gmtRefundPay: string
136
+ /** 退款金额(含各渠道) */
137
+ refundDetailItemList: Array<{
138
+ contributionType: string
139
+ amount: string
140
+ }> | null
141
+ }
142
+
143
+ // ---- 交易关闭 (alipay.trade.close) ----
144
+ export interface AlipayCloseParams {
145
+ outTradeNo?: string
146
+ tradeNo?: string
147
+ }
148
+
149
+ export interface AlipayCloseResult {
150
+ /** 支付宝交易号 */
151
+ tradeNo: string
152
+ /** 商户订单号 */
153
+ outTradeNo: string
154
+ }
155
+
156
+ // ---- 退款查询 (alipay.trade.fastpay.refund.query) ----
157
+ export interface AlipayRefundQueryParams {
158
+ outTradeNo?: string
159
+ tradeNo?: string
160
+ outRequestNo: string
161
+ }
162
+
163
+ export interface AlipayRefundQueryResult {
164
+ /** 支付宝交易号 */
165
+ tradeNo: string
166
+ /** 商户订单号 */
167
+ outTradeNo: string
168
+ /** 退款金额 */
169
+ refundAmount: string
170
+ /** 退款状态 */
171
+ refundStatus: string
172
+ /** 退款请求号 */
173
+ outRequestNo: string
174
+ /** 退款原因 */
175
+ refundReason: string
176
+ }
177
+
178
+ // ---- 异步通知 ----
179
+ export interface AlipayNotifyParams {
180
+ [key: string]: string | undefined
181
+ notifyTime: string
182
+ notifyType: string
183
+ notifyId: string
184
+ appId: string
185
+ charset: string
186
+ version: string
187
+ signType: string
188
+ sign: string
189
+ tradeNo: string
190
+ outTradeNo: string
191
+ outBizNo?: string
192
+ buyerId: string
193
+ buyerLogonId: string
194
+ sellerId: string
195
+ sellerEmail: string
196
+ tradeStatus: string
197
+ totalAmount: string
198
+ receiptAmount: string
199
+ invoiceAmount: string
200
+ buyerPayAmount: string
201
+ pointAmount: string
202
+ refundFee: string
203
+ subject: string
204
+ body: string
205
+ gmtCreate: string
206
+ gmtPayment: string
207
+ gmtClose: string
208
+ fundBillList: string
209
+ passbackParams: string
210
+ voucherDetailList: string
211
+ }
212
+
213
+ // ---- 通用 ----
214
+ export type TradeStatus =
215
+ | 'WAIT_BUYER_PAY'
216
+ | 'TRADE_CLOSED'
217
+ | 'TRADE_SUCCESS'
218
+ | 'TRADE_FINISHED'
219
+
220
+ export type AlipayKeyType = 'PKCS1' | 'PKCS8'
221
+
222
+ export interface AlipayClientOptions {
223
+ /** 应用 ID */
224
+ appId: string
225
+ /** 应用私钥(Node.js 使用 PKCS#1 格式) */
226
+ privateKey: string
227
+ /** 支付宝公钥 */
228
+ alipayPublicKey: string
229
+ /** 签名类型,默认 RSA2 */
230
+ signType?: AlipaySdkSignType
231
+ /** 网关地址,沙箱使用沙箱网关 */
232
+ gateway?: string
233
+ /** 异步通知地址 */
234
+ notifyUrl?: string
235
+ /** 同步跳转地址 */
236
+ returnUrl?: string
237
+ /** 私钥类型,默认 PKCS1(Node.js 使用 PKCS1) */
238
+ keyType?: AlipayKeyType
239
+ /** 请求超时时间,默认 5000ms */
240
+ timeout?: number
241
+ }
242
+
243
+ /** 电脑网站支付配置 */
244
+ export interface AlipayPagePayConfig {
245
+ /** 商户订单号 */
246
+ outTradeNo: string
247
+ /** 订单总金额,单位元 */
248
+ totalAmount: string
249
+ /** 订单标题 */
250
+ subject: string
251
+ /** 订单描述 */
252
+ body?: string
253
+ /** 公用回传参数 */
254
+ passbackParams?: string
255
+ }
256
+
257
+ /** 手机网站支付配置 */
258
+ export interface AlipayWapPayConfig {
259
+ /** 商户订单号 */
260
+ outTradeNo: string
261
+ /** 订单总金额,单位元 */
262
+ totalAmount: string
263
+ /** 订单标题 */
264
+ subject: string
265
+ /** 订单描述 */
266
+ body?: string
267
+ /** 公用回传参数 */
268
+ passbackParams?: string
269
+ /** 用户付款中途退出后返回的商户页面地址(wap 支付必填) */
270
+ quitUrl?: string
271
+ }
@@ -0,0 +1,55 @@
1
+ import type { AlipayClient } from './client'
2
+ import type { AlipayWapPayConfig, AlipayWapPayParams, AlipayWapPayResult } from './types'
3
+
4
+ /**
5
+ * 手机网站支付 (alipay.trade.wap.pay)
6
+ *
7
+ * 移动端浏览器内拉起支付宝收银台,生成表单 HTML 由前端提交跳转。
8
+ *
9
+ * ⚠️ 必须使用 pageExecute() 方法,禁止使用 exec()。
10
+ * ⚠️ 返回值为 HTML 表单字符串,前端必须渲染 form 并自动提交。
11
+ * ⚠️ 支付结果以异步通知或查询接口为准,不可依赖同步跳转。
12
+ */
13
+ export function createWapPay(client: AlipayClient) {
14
+ return {
15
+ /**
16
+ * 发起手机网站支付
17
+ * @param config 支付配置
18
+ * @returns 支付表单 HTML
19
+ */
20
+ async pay(config: AlipayWapPayConfig): Promise<AlipayWapPayResult> {
21
+ const { outTradeNo, totalAmount, subject, body, passbackParams, quitUrl } = config
22
+
23
+ const bizParams: AlipayWapPayParams = {
24
+ outTradeNo,
25
+ totalAmount,
26
+ subject,
27
+ productCode: 'QUICK_WAP_WAY',
28
+ body,
29
+ passbackParams,
30
+ quitUrl,
31
+ returnUrl: client.config.returnUrl,
32
+ notifyUrl: client.config.notifyUrl
33
+ }
34
+
35
+ const formHtml = client.sdk.pageExecute(
36
+ 'alipay.trade.wap.pay',
37
+ 'POST',
38
+ { bizContent: sanitizeParams(bizParams) }
39
+ )
40
+
41
+ return { formHtml }
42
+ }
43
+ }
44
+ }
45
+
46
+ /** 移除 undefined 字段 */
47
+ function sanitizeParams<T extends Record<string, any>>(params: T): Record<string, any> {
48
+ const result: Record<string, any> = {}
49
+ for (const [key, value] of Object.entries(params)) {
50
+ if (value !== undefined && value !== null) {
51
+ result[key] = value
52
+ }
53
+ }
54
+ return result
55
+ }
package/src/index.ts ADDED
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @vobs/payment 根入口
3
+ *
4
+ * - 通用工厂中 createRefund / createNotifyHandler 在两个提供商间同名,
5
+ * 统一通过 alipay.* / wechat.* 命名空间访问,避免同名不同客户端的隐式误用。
6
+ * - 顶层平铺导出跨提供商无歧义的符号(客户端、配置、错误类、插件、注入键,
7
+ * 以及名称唯一的工厂 createPagePay / createWapPay / createQuery / createPayment)。
8
+ */
9
+ export * as alipay from './alipay'
10
+ export * as wechat from './wechat'
11
+
12
+ export {
13
+ AlipayClient,
14
+ AlipayConfig,
15
+ AlipayApiError,
16
+ createPagePay,
17
+ createWapPay,
18
+ createQuery,
19
+ alipayPlugin,
20
+ useAlipay,
21
+ ALIPAY_KEY
22
+ } from './alipay'
23
+ export type {
24
+ AlipayClientOptions,
25
+ AlipayKeyType,
26
+ AlipaySdkConfig,
27
+ AlipaySdkSignType,
28
+ AlipayPagePayConfig,
29
+ AlipayPagePayParams,
30
+ AlipayPagePayResult,
31
+ AlipayWapPayConfig,
32
+ AlipayWapPayParams,
33
+ AlipayWapPayResult,
34
+ AlipayQueryParams,
35
+ AlipayQueryResult,
36
+ AlipayRefundParams,
37
+ AlipayRefundResult,
38
+ AlipayRefundQueryParams,
39
+ AlipayRefundQueryResult,
40
+ AlipayCloseParams,
41
+ AlipayCloseResult,
42
+ AlipayNotifyParams,
43
+ TradeStatus,
44
+ AlipayPluginOptions
45
+ } from './alipay'
46
+
47
+ export {
48
+ WechatClient,
49
+ WechatConfig,
50
+ WechatApiError,
51
+ createPayment,
52
+ wechatPlugin,
53
+ useWechat,
54
+ WECHAT_KEY
55
+ } from './wechat'
56
+ export type {
57
+ WechatClientOptions,
58
+ WechatPayParams,
59
+ WechatH5PayParams,
60
+ WechatJsapiPayResult,
61
+ WechatAppPayResult,
62
+ WechatNativePayResult,
63
+ WechatH5PayResult,
64
+ WechatQueryParams,
65
+ WechatQueryResult,
66
+ WechatRefundParams,
67
+ WechatRefundResult,
68
+ WechatRefundQueryParams,
69
+ WechatRefundAmount,
70
+ WechatOrderAmount,
71
+ WechatTradeState,
72
+ WechatRefundStatus,
73
+ WechatNotifyResource,
74
+ WechatNotifyHeaders,
75
+ WechatNotifyTransaction,
76
+ WechatNotifyRefund,
77
+ WechatPluginOptions
78
+ } from './wechat'
@@ -0,0 +1,68 @@
1
+ import { Wechatpay } from 'wechatpay-axios-plugin'
2
+ import { WechatConfig } from './config'
3
+ import type { WechatClientOptions } from './types'
4
+
5
+ /**
6
+ * 微信支付客户端封装
7
+ *
8
+ * 封装官方 wechatpay-axios-plugin 的 Wechatpay 实例,提供统一的生命周期管理。
9
+ * 可独立使用,也可通过 wechatPlugin 注册到 vobs 框架。
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const client = new WechatClient({
14
+ * mchid: '1900000000',
15
+ * serial: '商户API证书序列号',
16
+ * privateKey: '-----BEGIN PRIVATE KEY-----...',
17
+ * certs: { 'PUB_KEY_ID_xxx': '-----BEGIN PUBLIC KEY-----...' },
18
+ * appid: 'wx1234567890',
19
+ * apiv3Key: '32字节APIv3密钥',
20
+ * notifyUrl: 'https://your-domain.com/wechat/notify'
21
+ * })
22
+ * ```
23
+ */
24
+ export class WechatClient {
25
+ readonly config: WechatConfig
26
+ private _sdk: Wechatpay
27
+ private _disposed = false
28
+
29
+ constructor(options: WechatClientOptions) {
30
+ this.config = new WechatConfig(options)
31
+ this._sdk = this.createSdk(options)
32
+ }
33
+
34
+ /** 获取底层 Wechatpay 实例(链式 API:client.sdk.v3.pay.transactions.jsapi.post(...)) */
35
+ get sdk(): Wechatpay {
36
+ this.ensureActive()
37
+ return this._sdk
38
+ }
39
+
40
+ /** 更新配置并重建 SDK 实例 */
41
+ updateConfig(patch: Partial<WechatClientOptions>): void {
42
+ this.ensureActive()
43
+ this.config.update(patch)
44
+ this._sdk = this.createSdk(this.config.options as WechatClientOptions)
45
+ }
46
+
47
+ /** 销毁客户端 */
48
+ dispose(): void {
49
+ this._disposed = true
50
+ ;(this._sdk as any) = null
51
+ }
52
+
53
+ private createSdk(options: WechatClientOptions): Wechatpay {
54
+ return new Wechatpay({
55
+ mchid: options.mchid,
56
+ serial: options.serial,
57
+ privateKey: options.privateKey,
58
+ certs: options.certs,
59
+ timeout: options.timeout ?? 5000
60
+ })
61
+ }
62
+
63
+ private ensureActive(): void {
64
+ if (this._disposed) {
65
+ throw new Error('WechatClient: 客户端已销毁')
66
+ }
67
+ }
68
+ }
@@ -0,0 +1,81 @@
1
+ import type { WechatClientOptions } from './types'
2
+
3
+ /**
4
+ * 微信支付配置管理
5
+ * 遵循 vobs 生命周期管理:可创建、可校验、可更新、可替换
6
+ */
7
+ export class WechatConfig {
8
+ private _options: WechatClientOptions
9
+
10
+ constructor(options: WechatClientOptions) {
11
+ this.validate(options)
12
+ this._options = { ...options }
13
+ }
14
+
15
+ /** 获取完整配置 */
16
+ get options(): Readonly<WechatClientOptions> {
17
+ return this._options
18
+ }
19
+
20
+ /** 商户号 */
21
+ get mchid(): string {
22
+ return this._options.mchid
23
+ }
24
+
25
+ /** 应用 ID(公众号 / 小程序 / APP) */
26
+ get appid(): string {
27
+ return this._options.appid
28
+ }
29
+
30
+ /** 商户 API 证书序列号 */
31
+ get serial(): string {
32
+ return this._options.serial
33
+ }
34
+
35
+ /** APIv3 密钥(回调解密用) */
36
+ get apiv3Key(): string {
37
+ return this._options.apiv3Key
38
+ }
39
+
40
+ /** 异步通知地址 */
41
+ get notifyUrl(): string | undefined {
42
+ return this._options.notifyUrl
43
+ }
44
+
45
+ /** 更新配置(部分更新) */
46
+ update(patch: Partial<WechatClientOptions>): void {
47
+ const merged = { ...this._options, ...patch }
48
+ this.validate(merged)
49
+ this._options = merged
50
+ }
51
+
52
+ /** 替换配置 */
53
+ replace(options: WechatClientOptions): void {
54
+ this.validate(options)
55
+ this._options = { ...options }
56
+ }
57
+
58
+ private validate(options: WechatClientOptions): void {
59
+ if (!options.mchid) {
60
+ throw new Error('WechatConfig: mchid 不能为空')
61
+ }
62
+ if (!options.serial) {
63
+ throw new Error('WechatConfig: serial(商户 API 证书序列号)不能为空')
64
+ }
65
+ if (!options.privateKey) {
66
+ throw new Error('WechatConfig: privateKey(商户 API 私钥 PEM)不能为空')
67
+ }
68
+ if (!options.certs || Object.keys(options.certs).length === 0) {
69
+ throw new Error('WechatConfig: certs(平台证书/微信支付公钥 {序列号: PEM})不能为空')
70
+ }
71
+ if (!options.appid) {
72
+ throw new Error('WechatConfig: appid 不能为空')
73
+ }
74
+ if (!options.apiv3Key) {
75
+ throw new Error('WechatConfig: apiv3Key 不能为空')
76
+ }
77
+ if (options.apiv3Key.length !== 32) {
78
+ throw new Error('WechatConfig: apiv3Key 必须为 32 字节字符串')
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,30 @@
1
+ export { WechatClient } from './client'
2
+ export { WechatConfig } from './config'
3
+ export { WechatApiError } from './response'
4
+ export { createPayment } from './payment'
5
+ export { createNotifyHandler } from './notify'
6
+ export { createRefund } from './refund'
7
+ export { wechatPlugin, useWechat, WECHAT_KEY } from './plugin'
8
+ export type { WechatPluginOptions } from './plugin'
9
+ export type {
10
+ WechatClientOptions,
11
+ WechatPayParams,
12
+ WechatH5PayParams,
13
+ WechatJsapiPayResult,
14
+ WechatAppPayResult,
15
+ WechatNativePayResult,
16
+ WechatH5PayResult,
17
+ WechatQueryParams,
18
+ WechatQueryResult,
19
+ WechatRefundParams,
20
+ WechatRefundResult,
21
+ WechatRefundQueryParams,
22
+ WechatRefundAmount,
23
+ WechatOrderAmount,
24
+ WechatTradeState,
25
+ WechatRefundStatus,
26
+ WechatNotifyResource,
27
+ WechatNotifyHeaders,
28
+ WechatNotifyTransaction,
29
+ WechatNotifyRefund
30
+ } from './types'