@h-ai/cli 0.1.0-alpha.66 → 0.1.0-alpha.68

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 (198) hide show
  1. package/README.en.md +86 -241
  2. package/README.ja.md +86 -241
  3. package/README.md +86 -241
  4. package/dist/{src-RDQ2EIBT.js → chunk-FI56GONY.js} +32 -2669
  5. package/dist/chunk-FI56GONY.js.map +1 -0
  6. package/dist/chunk-MBPB37FR.js +1348 -0
  7. package/dist/chunk-MBPB37FR.js.map +1 -0
  8. package/dist/{chunk-QYX6V7H2.js → chunk-ZFNBUF77.js} +347 -276
  9. package/dist/chunk-ZFNBUF77.js.map +1 -0
  10. package/dist/cli-config-templates-W2LLPMB6.js +5 -0
  11. package/dist/{cli-config-templates-3XSFIXBP.js.map → cli-config-templates-W2LLPMB6.js.map} +1 -1
  12. package/dist/{cli-skill-templates-TSYEQTCY.js → cli-skill-templates-US5CCAJ4.js} +3 -3
  13. package/dist/{cli-skill-templates-TSYEQTCY.js.map → cli-skill-templates-US5CCAJ4.js.map} +1 -1
  14. package/dist/index.js +1304 -532
  15. package/dist/index.js.map +1 -1
  16. package/dist/metafile-esm.json +1 -0
  17. package/dist/src-DSJJXM2F.js +3849 -0
  18. package/dist/src-DSJJXM2F.js.map +1 -0
  19. package/package.json +9 -8
  20. package/templates/README.md +48 -145
  21. package/templates/apps/admin/messages/ja-JP.json +38 -0
  22. package/templates/apps/admin/src/routes/+layout.svelte.hbs +16 -6
  23. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +3 -3
  24. package/templates/apps/api/.dockerignore.hbs +14 -7
  25. package/templates/apps/api/.gitignore.hbs +7 -0
  26. package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +23 -2
  27. package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +2 -0
  28. package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +4 -1
  29. package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +33 -8
  30. package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +0 -10
  31. package/templates/apps/api/apps/{{projectName}}-service/config/_serv.yml.hbs +2 -1
  32. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -2
  33. package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +24 -11
  34. package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +8 -1
  35. package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +68 -11
  36. package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/index.ts.hbs +10 -2
  37. package/templates/apps/api/e2e/api-service.spec.ts.hbs +2 -2
  38. package/templates/apps/api/hai.build.json.hbs +1 -1
  39. package/templates/apps/api/images/app.Dockerfile.hbs +35 -0
  40. package/templates/apps/api/package.json.hbs +6 -1
  41. package/templates/apps/api/playwright.config.ts.hbs +15 -7
  42. package/templates/apps/fullstack/.dockerignore.hbs +14 -9
  43. package/templates/apps/fullstack/.gitignore.hbs +7 -0
  44. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +24 -6
  45. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +1 -0
  46. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/ja-JP.json.hbs +7 -0
  47. package/templates/apps/fullstack/apps/{{projectName}}-app/public/runtime-config.js.hbs +4 -0
  48. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +7 -1
  49. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +2 -2
  50. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +23 -5
  51. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/ja-JP.json.hbs +7 -0
  52. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +1 -1
  53. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +16 -6
  54. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/ja-JP.json.hbs +12 -0
  55. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +24 -6
  56. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/ja-JP.json.hbs +7 -0
  57. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +2 -2
  58. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +30 -9
  59. package/templates/apps/fullstack/hai.build.json.hbs +2 -2
  60. package/templates/apps/fullstack/images/app.Dockerfile.hbs +36 -0
  61. package/templates/apps/fullstack/images/web.Dockerfile.hbs +34 -0
  62. package/templates/apps/fullstack/package.json.hbs +3 -1
  63. package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +23 -2
  64. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +1 -1
  65. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +2 -0
  66. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +3 -0
  67. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +32 -8
  68. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +0 -6
  69. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +8 -0
  70. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +2 -1
  71. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +6 -0
  72. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +9 -5
  73. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +3 -2
  74. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +16 -1
  75. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +7 -3
  76. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +3 -0
  77. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +58 -7
  78. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +13 -3
  79. package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +7 -0
  80. package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +40 -14
  81. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/ja-JP.json.hbs +105 -0
  82. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +3 -3
  83. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +6 -6
  84. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +7 -7
  85. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +4 -4
  86. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +8 -8
  87. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +13 -14
  88. package/templates/apps/fullstack/playwright.config.ts.hbs +15 -6
  89. package/templates/apps/h5/messages/ja-JP.json +40 -0
  90. package/templates/apps/h5/src/routes/+layout.svelte.hbs +16 -5
  91. package/templates/apps/mobile-app/messages/ja-JP.json +36 -0
  92. package/templates/apps/mobile-app/src/App.svelte.hbs +15 -5
  93. package/templates/apps/mobile-app/src/lib/api.ts.hbs +173 -14
  94. package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +2 -2
  95. package/templates/apps/website/messages/ja-JP.json +32 -0
  96. package/templates/apps/website/src/routes/+layout.svelte.hbs +13 -5
  97. package/templates/apps/website/src/routes/services/+page.svelte.hbs +1 -1
  98. package/templates/base/.dockerignore.hbs +14 -8
  99. package/templates/base/.gitignore.hbs +7 -0
  100. package/templates/base/e2e/app.spec.ts.hbs +23 -8
  101. package/templates/base/hai.build.json.hbs +1 -1
  102. package/templates/base/{Dockerfile.hbs → images/app.Dockerfile.hbs} +19 -17
  103. package/templates/base/package.json.hbs +11 -3
  104. package/templates/base/playwright.config.ts +15 -4
  105. package/templates/base/src/hooks.server.ts.hbs +15 -6
  106. package/templates/base/src/lib/server/init.ts.hbs +139 -30
  107. package/templates/base/vite.config.ts.hbs +5 -3
  108. package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +11 -6
  109. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +18 -25
  110. package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +4 -0
  111. package/templates/i18n/project.inlang/settings.json +1 -1
  112. package/templates/shared/.gitattributes +6 -0
  113. package/templates/shared/e2e-env.ts +98 -0
  114. package/templates/shared/run-e2e.mjs +51 -12
  115. package/templates/skills/AGENTS.md +7 -3
  116. package/templates/skills/bridges/admin/AGENTS.md +6 -2
  117. package/templates/skills/bridges/api/AGENTS.md +3 -1
  118. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +5 -1
  119. package/templates/skills/bridges/h5/AGENTS.md +6 -2
  120. package/templates/skills/bridges/mobile-app/AGENTS.md +6 -2
  121. package/templates/skills/bridges/website/AGENTS.md +6 -2
  122. package/templates/skills/hai-ai/SKILL.md +8 -2
  123. package/templates/skills/hai-ai/guide.md +134 -60
  124. package/templates/skills/hai-ai/reference.md +51 -11
  125. package/templates/skills/hai-api-client/SKILL.md +15 -160
  126. package/templates/skills/hai-api-client/reference.md +178 -0
  127. package/templates/skills/hai-api-contract/SKILL.md +16 -273
  128. package/templates/skills/hai-api-contract/reference.md +280 -0
  129. package/templates/skills/hai-app-create/SKILL.md +6 -2
  130. package/templates/skills/hai-app-create/development.md +24 -8
  131. package/templates/skills/hai-app-create/reference.md +7 -5
  132. package/templates/skills/hai-app-review/SKILL.md +7 -3
  133. package/templates/skills/hai-app-review/differential.md +34 -0
  134. package/templates/skills/hai-app-tests/SKILL.md +6 -3
  135. package/templates/skills/hai-app-tests/reference.md +5 -5
  136. package/templates/skills/hai-app-tests/validation.md +38 -0
  137. package/templates/skills/hai-audit/SKILL.md +24 -147
  138. package/templates/skills/hai-audit/reference.md +148 -0
  139. package/templates/skills/hai-build/SKILL.md +14 -8
  140. package/templates/skills/hai-build/reference.md +16 -13
  141. package/templates/skills/hai-cache/SKILL.md +20 -181
  142. package/templates/skills/hai-cache/reference.md +229 -0
  143. package/templates/skills/hai-capacitor/SKILL.md +7 -4
  144. package/templates/skills/hai-capacitor/reference.md +15 -9
  145. package/templates/skills/hai-ci/SKILL.md +2 -0
  146. package/templates/skills/hai-core/SKILL.md +7 -3
  147. package/templates/skills/hai-core/reference.md +25 -5
  148. package/templates/skills/hai-crypto/SKILL.md +22 -250
  149. package/templates/skills/hai-crypto/reference.md +310 -0
  150. package/templates/skills/hai-datapipe/SKILL.md +16 -195
  151. package/templates/skills/hai-datapipe/reference.md +204 -0
  152. package/templates/skills/hai-deploy/SKILL.md +24 -54
  153. package/templates/skills/hai-deploy/middleware.md +51 -43
  154. package/templates/skills/hai-framework-sync/SKILL.md +2 -2
  155. package/templates/skills/hai-framework-sync/sync.md +1 -1
  156. package/templates/skills/hai-iam/SKILL.md +25 -11
  157. package/templates/skills/hai-iam/reference.md +181 -154
  158. package/templates/skills/hai-kit/SKILL.md +35 -174
  159. package/templates/skills/hai-kit/reference.md +190 -0
  160. package/templates/skills/hai-payment/SKILL.md +33 -263
  161. package/templates/skills/hai-payment/reference.md +295 -0
  162. package/templates/skills/hai-pr-review/SKILL.md +21 -88
  163. package/templates/skills/hai-reach/SKILL.md +6 -3
  164. package/templates/skills/hai-reach/reference.md +83 -22
  165. package/templates/skills/hai-reldb/SKILL.md +6 -3
  166. package/templates/skills/hai-reldb/reference.md +68 -25
  167. package/templates/skills/hai-scheduler/SKILL.md +18 -195
  168. package/templates/skills/hai-scheduler/reference.md +216 -0
  169. package/templates/skills/hai-serv/SKILL.md +25 -10
  170. package/templates/skills/hai-serv/reference.md +123 -87
  171. package/templates/skills/hai-spec-implement/SKILL.md +5 -1
  172. package/templates/skills/hai-spec-implement/evaluation.md +18 -0
  173. package/templates/skills/hai-spec-implement/handoff.md +47 -0
  174. package/templates/skills/hai-spec-implement/templates.md +5 -0
  175. package/templates/skills/hai-spec-implement/workflow.md +5 -3
  176. package/templates/skills/hai-spec-review/SKILL.md +4 -0
  177. package/templates/skills/hai-storage/SKILL.md +23 -238
  178. package/templates/skills/hai-storage/reference.md +282 -0
  179. package/templates/skills/hai-ui/SKILL.md +17 -3
  180. package/templates/skills/hai-ui/guide.md +3 -3
  181. package/templates/skills/hai-ui/reference.md +26 -11
  182. package/templates/skills/hai-ui-design/SKILL.md +31 -0
  183. package/templates/skills/hai-ui-design/patterns.md +26 -0
  184. package/templates/skills/hai-ui-review/SKILL.md +30 -0
  185. package/templates/skills/hai-ui-review/checklist.md +22 -0
  186. package/templates/skills/hai-vecdb/SKILL.md +14 -10
  187. package/templates/skills/hai-vecdb/reference.md +33 -3
  188. package/dist/chunk-FWN5B54L.js +0 -468
  189. package/dist/chunk-FWN5B54L.js.map +0 -1
  190. package/dist/chunk-QYX6V7H2.js.map +0 -1
  191. package/dist/cli-config-templates-3XSFIXBP.js +0 -5
  192. package/dist/src-RDQ2EIBT.js.map +0 -1
  193. package/templates/apps/api/Dockerfile.hbs +0 -35
  194. package/templates/apps/fullstack/Dockerfile.hbs +0 -57
  195. /package/templates/apps/fullstack/{docker → images/web}/19-runtime-config.envsh.hbs +0 -0
  196. /package/templates/apps/fullstack/{docker → images/web}/nginx.conf.hbs +0 -0
  197. /package/templates/apps/fullstack/{docker → images/web}/runtime-config.js.template.hbs +0 -0
  198. /package/templates/base/{docker → images/web}/nginx.conf.hbs +0 -0
@@ -1,271 +1,41 @@
1
1
  ---
2
2
  name: hai-payment
3
- description: "使用 @h-ai/payment 创建支付订单、验证回调、查单和退款,客户端调起支付。"
3
+ description: "接入微信、支付宝或 Stripe 的订单、回调验签、查单与退款,并处理客户端调起和幂等履约。"
4
4
  ---
5
5
 
6
6
  # hai-payment
7
7
 
8
8
  ## 能力契约
9
9
 
10
- | 项目 | 契约 |
11
- | --- | --- |
12
- | 能力 | 使用 @h-ai/payment 创建支付订单、验证回调、查单和退款,客户端调起支付 |
13
- | 适用场景 | 服务端支付集成及客户端调起流程 |
14
- | 输入 | Provider 配置、订单/退款参数、原始回调内容 |
15
- | 输出 | 服务端 HaiResult;客户端 invokePayment 按 client 契约使用 |
16
- | 限制 | 服务端保存凭据并验签;客户端完成不代表付款成功,以可信回调/查单为准。订单履约与重试需幂等。 |
17
-
18
- > `@h-ai/payment` 是 hai-framework 的统一支付模块,通过 Provider 模式支持微信支付、支付宝、Stripe。服务端处理订单和回调,客户端调起支付。
19
-
20
- ## 运行环境
21
-
22
- > **服务端 + 浏览器分工模块。** `payment.createOrder` / `payment.handleNotify` / `payment.refund` 等操作在 Node.js 端执行。浏览器端使用 `invokePayment()`(从 `@h-ai/payment/client` 导入)调起支付。
23
-
24
- ## 依赖
25
-
26
- | 模块 | 用途 | 是否必需 | 初始化要求 |
27
- | --- | --- | --- | --- |
28
- | `@h-ai/audit` | 审计日志(支付操作自动审计) | 可选 | 已初始化时自动写入审计日志 |
29
-
30
- ## 适用场景
31
-
32
- - 接入微信支付(JSAPI / H5 / Native / App)
33
- - 接入支付宝(H5 / App / PC)
34
- - 接入 Stripe(Checkout Session)
35
- - 支付回调验签与通知处理
36
- - 订单查询与退款
37
- - 客户端调起支付(Web / H5 / App)
38
-
39
- ## 使用步骤
40
-
41
- ### 1. 配置
42
-
43
- ```yaml
44
- # config/_payment.yml(自行创建)
45
- wechat:
46
- appId: ''
47
- mchId: ''
48
- apiV3Key: ''
49
- privateKey: ''
50
- serialNo: ''
51
- platformCert: '' # 可选,回调验签需要
52
-
53
- alipay:
54
- appId: ''
55
- privateKey: ''
56
- alipayPublicKey: ''
57
- signType: RSA2 # 可选,默认 RSA2
58
- sandbox: false # 可选,默认 false
59
-
60
- stripe:
61
- secretKey: ''
62
- webhookSecret: ''
63
- webhookToleranceSeconds: 300 # 可选,默认 300 秒
64
- ```
65
-
66
- 约定环境变量优先于 YAML,例如 `HAI_PAYMENT_WECHAT_APIV3KEY`、
67
- `HAI_PAYMENT_STRIPE_WEBHOOKSECRET`。生产密钥只放环境或密钥管理器。
68
-
69
- ### 2. 初始化(服务端)
70
-
71
- ```typescript
72
- import { payment } from '@h-ai/payment'
73
-
74
- const initResult = await payment.init({
75
- wechat: {
76
- appId: 'wx1234567890',
77
- mchId: '1600000000',
78
- apiV3Key: 'your-api-key-v3',
79
- privateKey: '-----BEGIN RSA PRIVATE KEY-----...',
80
- serialNo: 'CERT_SERIAL_NO',
81
- },
82
- alipay: {
83
- appId: '2021000000000000',
84
- privateKey: '-----BEGIN RSA PRIVATE KEY-----...',
85
- alipayPublicKey: '-----BEGIN PUBLIC KEY-----...',
86
- },
87
- })
88
- if (!initResult.success) {
89
- // 处理初始化错误
90
- }
91
- ```
92
-
93
- ### 3. 创建订单
94
-
95
- ```typescript
96
- const result = await payment.createOrder('wechat', {
97
- orderNo: 'ORDER_20250101_001',
98
- amount: 9900, // 单位:分
99
- description: '商品名称',
100
- tradeType: 'jsapi',
101
- userId: 'user_openid',
102
- notifyUrl: 'https://example.com/payment/notify/wechat',
103
- metadata: { source: 'web' },
104
- })
105
-
106
- if (result.success) {
107
- // result.data: PaymentOrder { provider, tradeType, clientParams, prepayId? }
108
- // clientParams 包含调起支付所需参数
109
- }
110
-
111
- // amount / totalAmount 必须是正整数(单位:分)
112
- ```
113
-
114
- ### 4. 处理支付回调
115
-
116
- ```typescript
117
- // API 路由:POST /payment/notify/:provider
118
- const result = await payment.handleNotify('wechat', {
119
- body: await request.text(),
120
- headers: Object.fromEntries(request.headers),
121
- })
122
-
123
- if (result.success) {
124
- // result.data: { orderNo, transactionId, amount, status, paidAt? }
125
- // 更新订单状态...
126
- }
127
- ```
128
-
129
- ### 5. 查询订单
130
-
131
- ```typescript
132
- const result = await payment.queryOrder('wechat', 'ORDER_20250101_001')
133
-
134
- if (result.success) {
135
- // result.data.status: 'pending' | 'paid' | 'closed' | 'refunded' | 'failed'
136
- }
137
- ```
138
-
139
- ### 6. 退款
140
-
141
- ```typescript
142
- const result = await payment.refund('wechat', {
143
- orderNo: 'ORDER_20250101_001',
144
- refundNo: 'REFUND_20250101_001',
145
- amount: 9900,
146
- totalAmount: 9900, // 微信退款必填
147
- reason: '用户退款',
148
- })
149
- ```
150
-
151
- ### 7. 客户端调起支付(浏览器)
152
-
153
- ```typescript
154
- import { invokePayment } from '@h-ai/payment/client'
155
-
156
- // 前端拿到服务端返回的 PaymentOrder 后调起支付
157
- const payResult = await invokePayment(orderResult.data)
158
- ```
159
-
160
- ## 核心 API(服务端)
161
-
162
- | API | 用途 | 返回值 |
163
- | ------------------------------------------------ | -------- | ----------------------------- |
164
- | `payment.init(config)` | 初始化 | `HaiResult<void>` |
165
- | `payment.close()` | 关闭 | `void` |
166
- | `payment.createOrder(providerName, input)` | 创建订单 | `HaiResult<PaymentOrder>` |
167
- | `payment.handleNotify(providerName, request)` | 处理回调 | `HaiResult<PaymentNotifyResult>` |
168
- | `payment.queryOrder(providerName, orderNo)` | 查询订单 | `HaiResult<OrderStatus>` |
169
- | `payment.refund(providerName, input)` | 退款 | `HaiResult<RefundResult>` |
170
- | `payment.closeOrder(providerName, orderNo)` | 关闭订单 | `HaiResult<void>` |
171
- | `payment.getProvider(name)` | 获取 Provider | `PaymentProvider \| undefined` |
172
- | `payment.registerProvider(provider)` | 注册自定义 Provider | `void` |
173
-
174
- ## 客户端 API
175
-
176
- | API | 用途 | 返回值 |
177
- | ------------------------ | -------- | ----------------------------- |
178
- | `invokePayment(options)` | 调起支付 | `HaiResult<InvokePaymentResult>` |
179
-
180
- ## 错误码 — `HaiPaymentError`
181
-
182
- | 错误码 | code | 说明 |
183
- |--------|------|------|
184
- | `HaiPaymentError.CREATE_ORDER_FAILED` | `hai:payment:001` | 创建订单失败 |
185
- | `HaiPaymentError.QUERY_ORDER_FAILED` | `hai:payment:002` | 查询订单失败 |
186
- | `HaiPaymentError.REFUND_FAILED` | `hai:payment:003` | 退款失败 |
187
- | `HaiPaymentError.CLOSE_ORDER_FAILED` | `hai:payment:004` | 关闭订单失败 |
188
- | `HaiPaymentError.NOT_INITIALIZED` | `hai:payment:010` | 模块未初始化 |
189
- | `HaiPaymentError.SIGN_FAILED` | `hai:payment:020` | 签名失败 |
190
- | `HaiPaymentError.PROVIDER_NOT_FOUND` | `hai:payment:030` | Provider 未注册 |
191
- | `HaiPaymentError.INVALID_AMOUNT` | `hai:payment:040` | 金额无效 |
192
- | `HaiPaymentError.NOTIFY_VERIFY_FAILED` | `hai:payment:050` | 回调验签失败 |
193
- | `HaiPaymentError.NOTIFY_PARSE_FAILED` | `hai:payment:051` | 回调解析失败 |
194
- | `HaiPaymentError.INVOKE_WEB_FAILED` | `hai:payment:060` | Web 端调起支付失败 |
195
- | `HaiPaymentError.INVOKE_APP_FAILED` | `hai:payment:061` | App 端调起支付失败 |
196
- | `HaiPaymentError.CONFIG_ERROR` | `hai:payment:070` | 配置无效 |
197
-
198
- ## Provider 模式
199
-
200
- 内置 Provider:
201
-
202
- - **wechat** — 微信支付 API v3
203
- - **alipay** — 支付宝开放平台
204
- - **stripe** — Stripe Checkout Session 模式
205
-
206
- 自定义 Provider 通过 `payment.registerProvider(provider)` 注册。
207
-
208
- ### HTTP API 契约
209
-
210
- ```typescript
211
- import { apiContract } from '@h-ai/api-contract'
212
-
213
- // apiContract.payment.orders.create — POST /payment/orders
214
- // apiContract.payment.orders.get — GET /payment/orders/{orderNo}
215
- // apiContract.payment.orders.refund — POST /payment/orders/{orderNo}/refunds
216
- // apiContract.payment.notifications.wechat — POST /payment/notifications/wechat
217
- ```
218
-
219
- ## 常见模式
220
-
221
- ### 服务端路由(SvelteKit)
222
-
223
- ```typescript
224
- import { kit } from '@h-ai/kit'
225
- // src/routes/api/v1/payment/create/+server.ts
226
- import { payment } from '@h-ai/payment'
227
-
228
- export const POST = kit.handler(async ({ request, locals }) => {
229
- const body = await request.json()
230
- const result = await payment.createOrder(body.provider, {
231
- orderNo: body.orderNo,
232
- amount: body.amount,
233
- description: body.description,
234
- tradeType: body.tradeType,
235
- userId: body.userId,
236
- notifyUrl: body.notifyUrl,
237
- })
238
-
239
- if (!result.success) {
240
- return kit.response.internalError(result.error.message)
241
- }
242
-
243
- return kit.response.ok(result.data, locals.requestId)
244
- })
245
- ```
246
-
247
- ### 完整支付流程
248
-
249
- ```
250
- 1. 客户端 → 服务端:创建订单(api.payment.orders.create({...}))
251
- 2. 服务端 → 支付平台:调用 Provider 创建预支付
252
- 3. 服务端 → 客户端:返回 providerData(含调起参数)
253
- 4. 客户端:invokePayment(providerData) 调起支付
254
- 5. 支付平台 → 服务端:异步回调通知
255
- 6. 服务端:handleNotify() 验签 + 更新订单状态
256
- 7. 客户端:轮询或回调查询订单状态
257
- ```
258
-
259
- ## 审计日志
260
-
261
- 关键支付操作(创建订单、回调、退款、关闭订单)成功后自动写入审计日志(依赖 `@h-ai/audit`),无需额外配置。`queryOrder` 为只读操作,不写审计日志。
262
-
263
- 内置 Provider 的 HTTP 请求默认带 15 秒超时;Stripe 可通过 `webhookToleranceSeconds` 调整 webhook 时间戳容忍窗口。
264
-
265
- ## 相关 Skills
266
-
267
- - `hai-kit`:服务端 API 路由与契约处理
268
- - `hai-api-client`:客户端契约调用
269
- - `hai-reldb`:订单持久化存储
270
- - `hai-audit`:审计日志(payment 内部自动调用)
271
- - `hai-core`:HaiResult 类型、日志、配置
10
+ | 项目 | 契约 |
11
+ | -------- | ------------------------------------------------------------------------------------------- |
12
+ | 能力 | 使用 @h-ai/payment 创建支付订单、验证回调、查单和退款,客户端调起支付 |
13
+ | 适用场景 | 服务端支付集成及客户端调起流程 |
14
+ | 输入 | Provider 配置、订单/退款参数、原始回调内容 |
15
+ | 输出 | 服务端 HaiResult;客户端 invokePayment 按 client 契约使用 |
16
+ | 限制 | 服务端保存凭据并验签;客户端完成不代表付款成功,以可信回调/查单为准。订单履约与重试需幂等。 |
17
+
18
+ ## 使用路径
19
+
20
+ 1. 服务端校验 Provider 配置后 init;微信必填 platformKeys(平台 serial/公钥ID→PEM,轮换保留新旧项),支付宝必填 sellerId 和可信 HTTPS returnUrl。Stripe 先初始化共享 reldb,记录渠道映射/幂等结果,关闭时顺序相反。真实凭据经私有配置注入;浏览器只导入 `/client`。
21
+ 2. 订单号、金额单位、商品与用户由服务端可信数据决定,先保存业务订单再创建支付。微信仅 jsapi,必填当前公众号 openid,微信/支付宝仅 CNY;支付宝仅 h5,用离线签名的 `{ gateway, fields }` 向固定网关 POST,成功仅表示生成页面参数。Stripe 仅 h5 托管 Checkout,配置 successUrl(必填)/cancelUrl(可选)。公共 TradeType 仅 jsapi/h5;App、Native、小程序及其它组合在联网前拒绝,客户端也拒绝。客户端先检查 success 再检查 invoked,不解析不可信 HTML,不接受任意 action/字段。
22
+ 3. 回调使用原始 body 与 headers 验签;核对商户/应用身份与严格时间格式,微信签名时钟仅容差 300 秒,支付宝允许合法跨日重试。所有 Provider 返回必填 eventId/currency,应用事务核对渠道、订单、金额、币种,以共享数据库原子提交订单状态/通知去重/outbox,提交后才应答成功;外部副作用需稳定键幂等。Stripe completed/unpaid 为 pending,只有 status=paid 才履约且防止乱序回退。客户端调起成功不代表付款完成。
23
+ 4. 查单、退款与回调重试覆盖成功、失败和重复路径;支付宝查单/退款/关单的 HTTP 200 不代表业务成功,缺失/错误 envelope、非 10000 业务码或关键字段缺失返回对应操作失败;退款 success 后还须检查 status,fund_change=N/缺失为 processing,向渠道确认退款结果。Stripe orderNo/refundNo 固定请求参数,不能覆盖 metadata.orderNo,未知结果超过 23 小时先核对渠道,不删除记录后盲重试。关单须确认 Session expired,已付款不能关闭;页面跳转不能作履约凭据。真实支付仅在用户授权范围内,最后 close。
24
+
25
+ 配置示例区分 `PaymentConfigInput` 与 Schema 解析后的 `PaymentConfig`;公开调用只使用包根入口或浏览器 `/client`。先判断 `HaiResult.success`,再判断付款/退款状态或客户端 `invoked`。源码内部签名/协议/幂等仓库例子仅用于解释实现,不应深层导入;类型示例不证明真实商户、网关或手机设备支付。
26
+
27
+ ## 按需参考
28
+
29
+ 按本次操作读取对应小节;以已安装版本的公开类型核验签名,示例中的业务变量由应用提供。
30
+
31
+ - [运行环境](reference.md#运行环境)
32
+ - [依赖](reference.md#依赖)
33
+ - [适用场景](reference.md#适用场景)
34
+ - [使用步骤](reference.md#使用步骤)
35
+ - [核心 API(服务端)](reference.md#核心-api服务端)
36
+ - [客户端 API](reference.md#客户端-api)
37
+ - [错误码 — `HaiPaymentError`](reference.md#错误码--haipaymenterror)
38
+ - [Provider 模式](reference.md#provider-模式)
39
+ - [常见模式](reference.md#常见模式)
40
+ - [审计日志](reference.md#审计日志)
41
+ - [相关 Skills](reference.md#相关-skills)
@@ -0,0 +1,295 @@
1
+ # hai-payment 参考
2
+
3
+ > `@h-ai/payment` 是 hai-framework 的统一支付模块,通过 Provider 模式支持微信支付、支付宝、Stripe。服务端处理订单和回调,客户端调起支付。
4
+
5
+ 公开类型示例按实际包入口校验:初始化输入为 `PaymentConfigInput`,配置 Schema 输出为 `PaymentConfig`;`HaiPaymentError` 的单个成员是错误定义,比较 `result.error.code` 时使用其 `.code`。私有协议、签名、操作仓库不属于应用导入入口。JSDoc 的类型校验不会执行渠道支付或业务履约。
6
+
7
+ ## 运行环境
8
+
9
+ > **服务端 + 浏览器分工模块。** `payment.createOrder` / `payment.handleNotify` / `payment.refund` 等操作在 Node.js 端执行。浏览器端使用 `invokePayment()`(从 `@h-ai/payment/client` 导入)调起支付。
10
+
11
+ ## 依赖
12
+
13
+ | 模块 | 用途 | 是否必需 | 初始化要求 |
14
+ | ------------- | ----------------------------------- | ------------------ | ---------------------------------------- |
15
+ | `@h-ai/audit` | 审计日志(支付操作自动审计) | 可选 | 已初始化时自动写入审计日志 |
16
+ | `@h-ai/reldb` | Stripe 渠道映射、操作预留与幂等结果 | 启用 Stripe 时必需 | 先初始化共享 DB;payment 关闭后再关闭 DB |
17
+
18
+ ## 适用场景
19
+
20
+ - 接入微信公众号 JSAPI 支付(需 openid/WeixinJSBridge)
21
+ - 接入支付宝 H5(WAP 离线签名表单)
22
+ - 接入 Stripe(Checkout Session)
23
+ - 支付回调验签与通知处理
24
+ - 订单查询与退款
25
+ - 客户端调起支付(微信内置浏览器 / H5 跳转)
26
+
27
+ ## 使用步骤
28
+
29
+ ### 1. 配置
30
+
31
+ ```yaml
32
+ # config/_payment.yml(自行创建)
33
+ wechat:
34
+ appId: ''
35
+ mchId: ''
36
+ apiV3Key: ''
37
+ privateKey: ''
38
+ serialNo: ''
39
+ platformKeys: # 必填,按通知 Wechatpay-Serial 精确选择受信平台证书/公钥
40
+ PUB_KEY_ID_123: '' # 平台公钥 PEM;证书使用其真实序列号作为 key
41
+
42
+ alipay:
43
+ appId: ''
44
+ sellerId: '' # 必填,验签后核对 seller_id
45
+ privateKey: ''
46
+ alipayPublicKey: ''
47
+ returnUrl: 'https://app.example/payment/return' # 必填 HTTPS,不能作为付款证明
48
+ signType: RSA2 # 可选,默认 RSA2
49
+ sandbox: false # 可选,默认 false
50
+
51
+ stripe:
52
+ secretKey: ''
53
+ webhookSecret: ''
54
+ successUrl: 'https://app.example/payment/success?session_id={CHECKOUT_SESSION_ID}' # 必填
55
+ cancelUrl: 'https://app.example/payment/cancel' # 可选
56
+ webhookToleranceSeconds: 300 # 可选,默认 300 秒
57
+ ```
58
+
59
+ Stripe 的 secretKey 必须为 sk/rk 的 test/live 服务端密钥;受限密钥须允许读取账户。只实现 payment + hosted_page + tradeType=h5,必填 successUrl、可选 cancelUrl 均来自服务端配置且必须为 HTTP(S)。不支持 embedded/elements 或 App/JSAPI/Native 等支付场景,不向客户端提供改变模式/跳转地址的接口。API 固定为 2026-09-30.endive;启用前初始化共享 reldb,不能给不同节点配置各自的 SQLite 文件。
60
+
61
+ 内置创建模式仅保留上表组合;公开 `TradeType` 为 `jsapi | h5`,App、Native、小程序及其它组合均在请求渠道前返回 `UNSUPPORTED_TRADE_TYPE`。微信 JSAPI 必须提供当前公众号的 `userId`(openid),微信与支付宝仅接受 CNY。微信下单缺失有效 `prepay_id` 时失败。支付宝 `createOrder` 只生成已签名的页面请求参数,不表示渠道已受理或已付款;返回 `{ gateway, fields }`,浏览器向固定正式/沙箱网关 POST 全部签名字段,不解析 HTML,也不接收任意 action。配置 `alipay.returnUrl` 必填且为 HTTPS,`HAI_PAYMENT_ALIPAY_RETURNURL` 可覆盖;回跳不代表付款成功。客户端先检查 `success`,再检查 `data.invoked`;微信桥接对象未就绪时 `invoked=false`,已调起后的取消回调也不代表付款。
62
+
63
+ 协议依据:[微信 JSAPI 下单](https://pay.wechatpay.cn/doc/v3/merchant/4012791897)、[JSAPI 调起](https://pay.wechatpay.cn/doc/v3/merchant/4012791857)、[支付宝官方 Node SDK pageExecute](https://github.com/alipay/alipay-sdk-nodejs-all#pageexecute-示例代码)。定向测试验证请求/签名形状、真实 RSA 验签和 jsdom 表单提交;未使用真实商户凭据、渠道沙箱账户或手机设备,不能据此宣称已完成真实支付验收。
64
+
65
+ 约定环境变量优先于 YAML,例如 `HAI_PAYMENT_WECHAT_APIV3KEY`、
66
+ `HAI_PAYMENT_STRIPE_WEBHOOKSECRET`。生产密钥只放环境或密钥管理器。
67
+
68
+ ### 2. 初始化(服务端)
69
+
70
+ ```typescript
71
+ import { payment } from '@h-ai/payment'
72
+
73
+ const initResult = await payment.init({
74
+ wechat: {
75
+ appId: 'wx1234567890',
76
+ mchId: '1600000000',
77
+ apiV3Key: 'your-api-key-v3',
78
+ privateKey: '-----BEGIN RSA PRIVATE KEY-----...',
79
+ serialNo: 'CERT_SERIAL_NO',
80
+ platformKeys: { PUB_KEY_ID_123: '-----BEGIN PUBLIC KEY-----...' },
81
+ },
82
+ alipay: {
83
+ appId: '2021000000000000',
84
+ sellerId: '2088000000000000',
85
+ privateKey: '-----BEGIN RSA PRIVATE KEY-----...',
86
+ alipayPublicKey: '-----BEGIN PUBLIC KEY-----...',
87
+ returnUrl: 'https://app.example/payment/return',
88
+ },
89
+ })
90
+ if (!initResult.success) {
91
+ // 处理初始化错误
92
+ }
93
+ ```
94
+
95
+ ### 3. 创建订单
96
+
97
+ ```typescript
98
+ const result = await payment.createOrder('wechat', {
99
+ orderNo: 'ORDER_20250101_001',
100
+ amount: 9900, // 单位:分
101
+ description: '商品名称',
102
+ tradeType: 'jsapi',
103
+ userId: 'user_openid',
104
+ notifyUrl: 'https://example.com/payment/notify/wechat',
105
+ metadata: { source: 'web' },
106
+ })
107
+
108
+ if (result.success) {
109
+ // result.data: PaymentOrder { provider, tradeType, clientParams, prepayId? }
110
+ // clientParams 包含调起支付所需参数
111
+ }
112
+
113
+ // amount / totalAmount 必须是正整数(单位:分)
114
+ ```
115
+
116
+ ### 4. 处理支付回调
117
+
118
+ ```typescript
119
+ // API 路由:POST /payment/notify/:provider
120
+ const result = await payment.handleNotify('wechat', {
121
+ body: await request.text(),
122
+ headers: Object.fromEntries(request.headers),
123
+ })
124
+
125
+ if (result.success) {
126
+ // success 仅表示验签解析成功;Stripe completed/unpaid 仍是 pending。
127
+ // 在共享数据库事务中核对渠道、订单、amount、currency,按渠道/商户命名空间持久去重 eventId。
128
+ // 仅 status=paid 可履约;乱序 pending/failed 不得回退已支付/已退款订单。
129
+ }
130
+ ```
131
+
132
+ Stripe 只消费 payment-mode Checkout Session 的 `completed`、`async_payment_succeeded`、`async_payment_failed`、`expired` 事件,其它事件或缺失订单号/金额/币种返回 `NOTIFY_PARSE_FAILED`。结果的 `eventId` 用于持久去重,`currency` 为大写,`transactionId` 为 Session ID。只有 paid 结果返回 `paidAt`,取成功事件的 created 时间;Provider 不维护业务订单或进程内去重集合。
133
+
134
+ 所有 Provider(含自定义实现)都必须返回 eventId/currency:微信 id、支付宝 notify_id、Stripe event.id;支付宝 currency 固定 CNY。微信只处理 TRANSACTION.SUCCESS/transaction,验签后继续校验 appid/mchid,按 Wechatpay-Serial 精确选择 platformKeys 项,检查证书序列号及有效期、严格整数签名时钟与当前节点相差不超过 300 秒。轮换期间所有节点同时保存新旧项;未知 serial 不能自动下载并信任。支付宝核对 app_id/seller_id/配置签名算法,拒绝重复表单字段,按北京时间严格解析真实日期;notify_id 跨日重试不变,不能对原始通知时间套五分钟有效期。支付宝请求使用 Asia/Shanghai 和 POST form body,不能把签名/订单内容放 URL。Stripe 按密钥校验 test/live,支持轮换期多个 v1 签名,只支持当前账户,拒绝 Connect/组织 context 事件。
135
+
136
+ 接入应用应把“业务订单 pending→paid 的条件更新 + 唯一 eventId 记录 + 唯一履约 outbox”放进共享数据库同一个事务;所有 HaiResult 失败必须抛错使 reldb.tx.wrap 回滚,数据库提交后才应答渠道成功。条件须核对已存渠道、金额、币种和交易号,重复已支付通知或晚到 pending 不重复履约,已退款状态也不能倒退。订单号不得删除后复用,切换商户不能复用旧业务订单命名空间。外部发货等由 outbox 消费者携带稳定 outbox ID 幂等调用,不能在数据库事务中直接调用后宣称跨系统只执行一次。
137
+
138
+ ### 5. 查询订单
139
+
140
+ Stripe 创建操作将 orderNo 与 Session ID 持久绑定,查单/退款通过该 ID 读取并核对订单号、金额和币种,不使用 metadata 列表首项猜测。metadata.orderNo 为保留字段。orderNo/refundNo 的请求参数不能在重试时改变,渠道 POST 使用稳定 Idempotency-Key。
141
+
142
+ Stripe closeOrder 会通过可信映射读取 Session,只有 open/unpaid 才调用 expire;已 expired 幂等成功,complete/paid 失败。并发关闭或响应丢失后必须重读确认 expired,不能把“已发送请求”当关闭成功。successUrl/cancelUrl 的页面跳转不代表已付款或已经关单,业务仍以可信状态为准。
143
+
144
+ 响应丢失或落库失败会保留未知记录,只能在数据库时钟的 23 小时安全窗口内沿用同一键重试;窗口之外先核对渠道结果并修复记录,不删除后重发。成功结果长期保留,不按缓存 TTL 清理。Stripe 仅保存渠道操作结果,宿主业务订单、回调去重与履约事务仍需自己实现。
145
+
146
+ ```typescript
147
+ const result = await payment.queryOrder('wechat', 'ORDER_20250101_001')
148
+
149
+ if (result.success) {
150
+ // result.data.status: 'pending' | 'paid' | 'closed' | 'refunded' | 'failed'
151
+ }
152
+ ```
153
+
154
+ ### 6. 退款
155
+
156
+ 支付宝查单/退款/关单会验证方法对应的 envelope、字符串 code=10000、关键字段和订单号;HTTP 200 业务错误返回对应操作的 HaiResult 失败。错误 cause 不含原始响应或 msg/sub_msg。退款 `success: true` 表示请求受理,仍须检查 data.status:fund_change=Y 才为 success,N/缺失为 processing,需自行通过渠道退款查询确认(本模块没有退款查询 API)。refund_fee 是累计退款额,refundId 是原交易号,以 refundNo 区分本次退款且重试保持参数不变。关单先检查 result.success 再更新业务订单。
157
+
158
+ ```typescript
159
+ const result = await payment.refund('wechat', {
160
+ orderNo: 'ORDER_20250101_001',
161
+ refundNo: 'REFUND_20250101_001',
162
+ amount: 9900,
163
+ totalAmount: 9900, // 微信退款必填
164
+ reason: '用户退款',
165
+ })
166
+ ```
167
+
168
+ ### 7. 客户端调起支付(浏览器)
169
+
170
+ ```typescript
171
+ import { invokePayment } from '@h-ai/payment/client'
172
+
173
+ // 前端拿到服务端返回的 PaymentOrder 后调起支付
174
+ if (!orderResult.success)
175
+ throw new Error(orderResult.error.message)
176
+ const payResult = await invokePayment(orderResult.data)
177
+ if (!payResult.success)
178
+ throw new Error(payResult.error.message)
179
+ if (!payResult.data.invoked)
180
+ throw new Error(payResult.data.message)
181
+ ```
182
+
183
+ ## 核心 API(服务端)
184
+
185
+ | API | 用途 | 返回值 |
186
+ | --------------------------------------------- | ------------------- | -------------------------------- |
187
+ | `payment.init(config)` | 初始化 | `HaiResult<void>` |
188
+ | `payment.close()` | 关闭 | `void` |
189
+ | `payment.createOrder(providerName, input)` | 创建订单 | `HaiResult<PaymentOrder>` |
190
+ | `payment.handleNotify(providerName, request)` | 处理回调 | `HaiResult<PaymentNotifyResult>` |
191
+ | `payment.queryOrder(providerName, orderNo)` | 查询订单 | `HaiResult<OrderStatus>` |
192
+ | `payment.refund(providerName, input)` | 退款 | `HaiResult<RefundResult>` |
193
+ | `payment.closeOrder(providerName, orderNo)` | 关闭订单 | `HaiResult<void>` |
194
+ | `payment.getProvider(name)` | 获取 Provider | `PaymentProvider \| undefined` |
195
+ | `payment.registerProvider(provider)` | 注册自定义 Provider | `void` |
196
+
197
+ ## 客户端 API
198
+
199
+ | API | 用途 | 返回值 |
200
+ | ------------------------ | -------- | -------------------------------- |
201
+ | `invokePayment(options)` | 调起支付 | `HaiResult<InvokePaymentResult>` |
202
+
203
+ ## 错误码 — `HaiPaymentError`
204
+
205
+ | 错误码 | code | 说明 |
206
+ | ---------------------------------------- | ----------------- | ------------------------- |
207
+ | `HaiPaymentError.CREATE_ORDER_FAILED` | `hai:payment:001` | 创建订单失败 |
208
+ | `HaiPaymentError.QUERY_ORDER_FAILED` | `hai:payment:002` | 查询订单失败 |
209
+ | `HaiPaymentError.REFUND_FAILED` | `hai:payment:003` | 退款失败 |
210
+ | `HaiPaymentError.CLOSE_ORDER_FAILED` | `hai:payment:004` | 关闭订单失败 |
211
+ | `HaiPaymentError.NOT_INITIALIZED` | `hai:payment:010` | 模块未初始化 |
212
+ | `HaiPaymentError.SIGN_FAILED` | `hai:payment:020` | 签名失败 |
213
+ | `HaiPaymentError.PROVIDER_NOT_FOUND` | `hai:payment:030` | Provider 未注册 |
214
+ | `HaiPaymentError.INVALID_AMOUNT` | `hai:payment:040` | 金额无效 |
215
+ | `HaiPaymentError.UNSUPPORTED_TRADE_TYPE` | `hai:payment:041` | 渠道不支持该模式 |
216
+ | `HaiPaymentError.INVALID_INPUT` | `hai:payment:042` | openid/币种等下单参数无效 |
217
+ | `HaiPaymentError.NOTIFY_VERIFY_FAILED` | `hai:payment:050` | 回调验签失败 |
218
+ | `HaiPaymentError.NOTIFY_PARSE_FAILED` | `hai:payment:051` | 回调解析失败 |
219
+ | `HaiPaymentError.INVOKE_WEB_FAILED` | `hai:payment:060` | Web 端调起支付失败 |
220
+ | `HaiPaymentError.CONFIG_ERROR` | `hai:payment:070` | 配置无效 |
221
+
222
+ ## Provider 模式
223
+
224
+ 内置 Provider:
225
+
226
+ - **wechat** — 微信支付 API v3
227
+ - **alipay** — 支付宝开放平台
228
+ - **stripe** — Stripe Checkout Session 模式
229
+
230
+ 自定义 Provider 通过 `payment.registerProvider(provider)` 注册。
231
+
232
+ ### HTTP API 契约
233
+
234
+ ```typescript
235
+ import { apiContract } from '@h-ai/api-contract'
236
+
237
+ // apiContract.payment.orders.create — POST /payment/orders
238
+ // apiContract.payment.orders.get — GET /payment/orders/{orderNo}
239
+ // apiContract.payment.orders.refund — POST /payment/orders/{orderNo}/refunds
240
+ // apiContract.payment.notifications.wechat — POST /payment/notifications/wechat
241
+ ```
242
+
243
+ ## 常见模式
244
+
245
+ ### 服务端路由(SvelteKit)
246
+
247
+ ```typescript
248
+ import { kit } from '@h-ai/kit'
249
+ // src/routes/api/v1/payment/create/+server.ts
250
+ import { payment } from '@h-ai/payment'
251
+
252
+ export const POST = kit.handler(async ({ request, locals }) => {
253
+ const body = await request.json()
254
+ const result = await payment.createOrder(body.provider, {
255
+ orderNo: body.orderNo,
256
+ amount: body.amount,
257
+ description: body.description,
258
+ tradeType: body.tradeType,
259
+ userId: body.userId,
260
+ notifyUrl: body.notifyUrl,
261
+ })
262
+
263
+ if (!result.success) {
264
+ return kit.response.internalError(result.error.message)
265
+ }
266
+
267
+ return kit.response.ok(result.data, locals.requestId)
268
+ })
269
+ ```
270
+
271
+ ### 完整支付流程
272
+
273
+ ```
274
+ 1. 客户端 → 服务端:创建订单(api.payment.orders.create({...}))
275
+ 2. 服务端 → 支付平台:调用 Provider 创建预支付
276
+ 3. 服务端 → 客户端:返回 providerData(含调起参数)
277
+ 4. 客户端:invokePayment(providerData) 调起支付
278
+ 5. 支付平台 → 服务端:异步回调通知
279
+ 6. 服务端:handleNotify() 验签解析,业务层持久核对并幂等更新订单状态
280
+ 7. 客户端:轮询或回调查询订单状态
281
+ ```
282
+
283
+ ## 审计日志
284
+
285
+ 关键支付操作(创建订单、回调、退款、关闭订单)成功后自动写入审计日志(依赖 `@h-ai/audit`),无需额外配置。`queryOrder` 为只读操作,不写审计日志。
286
+
287
+ 内置 Provider 的 HTTP 请求默认带 15 秒超时;Stripe 可通过 `webhookToleranceSeconds` 调整 webhook 时间戳容忍窗口。
288
+
289
+ ## 相关 Skills
290
+
291
+ - `hai-kit`:服务端 API 路由与契约处理
292
+ - `hai-api-client`:客户端契约调用
293
+ - `hai-reldb`:订单持久化存储
294
+ - `hai-audit`:审计日志(payment 内部自动调用)
295
+ - `hai-core`:HaiResult 类型、日志、配置