payment-kit 1.27.1 → 1.28.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.
- package/__blocklet__.js +37 -0
- package/api/ocap-1.30-subpath-shims.d.ts +35 -0
- package/api/src/crons/index.ts +10 -0
- package/api/src/crons/metering-subscription-detection.ts +12 -14
- package/api/src/crons/overdue-detection.ts +51 -74
- package/api/src/integrations/arcblock/nft.ts +6 -2
- package/api/src/integrations/arcblock/stake.ts +3 -2
- package/api/src/integrations/arcblock/token.ts +4 -4
- package/api/src/integrations/blocklet/notification.ts +1 -1
- package/api/src/integrations/ethereum/tx.ts +29 -0
- package/api/src/integrations/stripe/handlers/invoice.ts +70 -53
- package/api/src/integrations/stripe/handlers/payment-intent.ts +8 -1
- package/api/src/integrations/stripe/resource.ts +8 -0
- package/api/src/libs/audit.ts +32 -16
- package/api/src/libs/auth.ts +49 -2
- package/api/src/libs/chain-error.ts +31 -0
- package/api/src/libs/error.ts +15 -0
- package/api/src/libs/event.ts +42 -1
- package/api/src/libs/invoice.ts +69 -34
- package/api/src/libs/notification/template/customer-auto-recharge-daily-limit-exceeded.ts +1 -3
- package/api/src/libs/notification/template/customer-auto-recharge-failed.ts +1 -3
- package/api/src/libs/notification/template/customer-credit-grant-granted.ts +1 -3
- package/api/src/libs/notification/template/customer-credit-insufficient.ts +1 -3
- package/api/src/libs/notification/template/customer-credit-low-balance.ts +1 -3
- package/api/src/libs/notification/template/customer-revenue-succeeded.ts +1 -3
- package/api/src/libs/notification/template/customer-reward-succeeded.ts +1 -3
- package/api/src/libs/notification/template/one-time-payment-refund-succeeded.ts +1 -3
- package/api/src/libs/notification/template/one-time-payment-succeeded.ts +1 -3
- package/api/src/libs/notification/template/subscription-renew-failed.ts +1 -3
- package/api/src/libs/notification/template/subscription-slippage-exceeded.ts +1 -3
- package/api/src/libs/notification/template/subscription-slippage-warning.ts +1 -3
- package/api/src/libs/notification/template/subscription-succeeded.ts +1 -1
- package/api/src/libs/pagination.ts +14 -9
- package/api/src/libs/payment.ts +25 -10
- package/api/src/libs/session.ts +1 -1
- package/api/src/libs/timing.ts +35 -0
- package/api/src/libs/util.ts +16 -15
- package/api/src/libs/wallet-migration.ts +72 -53
- package/api/src/queues/auto-recharge.ts +1 -1
- package/api/src/queues/credit-consume.ts +94 -12
- package/api/src/queues/credit-grant.ts +4 -0
- package/api/src/queues/event.ts +14 -2
- package/api/src/queues/invoice.ts +1 -0
- package/api/src/queues/payment.ts +83 -15
- package/api/src/queues/refund.ts +84 -71
- package/api/src/queues/subscription.ts +1 -0
- package/api/src/routes/checkout-sessions.ts +82 -43
- package/api/src/routes/connect/change-payment.ts +2 -0
- package/api/src/routes/connect/change-plan.ts +2 -0
- package/api/src/routes/connect/pay.ts +12 -3
- package/api/src/routes/connect/setup.ts +3 -1
- package/api/src/routes/connect/shared.ts +52 -39
- package/api/src/routes/connect/subscribe.ts +4 -1
- package/api/src/routes/credit-grants.ts +25 -17
- package/api/src/routes/donations.ts +2 -2
- package/api/src/routes/meter-events.ts +16 -6
- package/api/src/routes/payment-links.ts +1 -1
- package/api/src/routes/payment-methods.ts +1 -1
- package/api/src/routes/settings.ts +1 -1
- package/api/src/routes/tax-rates.ts +1 -1
- package/api/src/store/models/customer.ts +23 -1
- package/api/src/store/models/payment-method.ts +4 -0
- package/api/src/store/models/price.ts +23 -14
- package/api/tests/libs/wallet-migration.spec.ts +4 -4
- package/api/tests/queues/credit-consume-batch.spec.ts +5 -2
- package/api/tests/queues/credit-consume.spec.ts +8 -4
- package/api/tests/routes/credit-grants.spec.ts +1 -0
- package/blocklet.yml +1 -1
- package/cloudflare/MIGRATION-CHALLENGES.md +676 -0
- package/cloudflare/MIGRATION-RUNBOOK.md +777 -0
- package/cloudflare/README.md +499 -0
- package/cloudflare/STAGING-MIGRATION-GUIDE.md +602 -0
- package/cloudflare/build.ts +151 -0
- package/cloudflare/did-connect-auth.ts +527 -0
- package/cloudflare/docs/2026-04-22-sdk-1.30.9-upgrade-retro.md +324 -0
- package/cloudflare/docs/2026-04-24-queue-ops-followup.md +218 -0
- package/cloudflare/docs/cf-queues-ops-alert-analysis.md +663 -0
- package/cloudflare/docs/cf-workers-local-dev-and-fixes.md +284 -0
- package/cloudflare/docs/cleanup-tasks-2026-05.md +62 -0
- package/cloudflare/docs/payment-kit-platform-analysis-2026-04-20.md +354 -0
- package/cloudflare/frontend-shims/buffer-polyfill.ts +9 -0
- package/cloudflare/frontend-shims/js-sdk.ts +43 -0
- package/cloudflare/frontend-shims/mime-types.ts +46 -0
- package/cloudflare/frontend-shims/session.ts +24 -0
- package/cloudflare/frontend-shims/vite-plugin-noop.ts +6 -0
- package/cloudflare/index.html +40 -0
- package/cloudflare/migrate-to-d1.js +252 -0
- package/cloudflare/migrations/0001_initial_schema.sql +82 -0
- package/cloudflare/migrations/0002_indexes.sql +75 -0
- package/cloudflare/migrations/0003_locks_and_constraints.sql +18 -0
- package/cloudflare/run-build.js +390 -0
- package/cloudflare/scripts/test-decrypt.js +102 -0
- package/cloudflare/shims/arcblock-ws.ts +20 -0
- package/cloudflare/shims/axios-http-adapter.ts +4 -0
- package/cloudflare/shims/axios-lite.ts +117 -0
- package/cloudflare/shims/blocklet-sdk/auth-service.ts +33 -0
- package/cloudflare/shims/blocklet-sdk/cdn.ts +3 -0
- package/cloudflare/shims/blocklet-sdk/component-api.ts +35 -0
- package/cloudflare/shims/blocklet-sdk/component.ts +18 -0
- package/cloudflare/shims/blocklet-sdk/config.ts +8 -0
- package/cloudflare/shims/blocklet-sdk/did.ts +14 -0
- package/cloudflare/shims/blocklet-sdk/env.ts +12 -0
- package/cloudflare/shims/blocklet-sdk/eventbus.ts +3 -0
- package/cloudflare/shims/blocklet-sdk/fallback.ts +3 -0
- package/cloudflare/shims/blocklet-sdk/index.ts +11 -0
- package/cloudflare/shims/blocklet-sdk/logger.ts +11 -0
- package/cloudflare/shims/blocklet-sdk/middlewares.ts +15 -0
- package/cloudflare/shims/blocklet-sdk/notification.ts +11 -0
- package/cloudflare/shims/blocklet-sdk/security.ts +53 -0
- package/cloudflare/shims/blocklet-sdk/session.ts +8 -0
- package/cloudflare/shims/blocklet-sdk/verify-sign.ts +38 -0
- package/cloudflare/shims/blocklet-sdk/wallet-authenticator.ts +3 -0
- package/cloudflare/shims/blocklet-sdk/wallet-handler.ts +6 -0
- package/cloudflare/shims/blocklet-sdk/wallet.ts +103 -0
- package/cloudflare/shims/cookie-parser.ts +3 -0
- package/cloudflare/shims/cors.ts +21 -0
- package/cloudflare/shims/cron.ts +189 -0
- package/cloudflare/shims/crypto-js-warn.ts +7 -0
- package/cloudflare/shims/did-space-js.ts +17 -0
- package/cloudflare/shims/did-space.ts +11 -0
- package/cloudflare/shims/error.ts +18 -0
- package/cloudflare/shims/express-compat/index.ts +80 -0
- package/cloudflare/shims/express-compat/types.ts +41 -0
- package/cloudflare/shims/fastq.ts +105 -0
- package/cloudflare/shims/lock.ts +115 -0
- package/cloudflare/shims/mime-types.ts +56 -0
- package/cloudflare/shims/nedb-storage.ts +9 -0
- package/cloudflare/shims/node-child-process.ts +9 -0
- package/cloudflare/shims/node-fs.ts +20 -0
- package/cloudflare/shims/node-http.ts +13 -0
- package/cloudflare/shims/node-https.ts +4 -0
- package/cloudflare/shims/node-misc.ts +15 -0
- package/cloudflare/shims/node-net.ts +8 -0
- package/cloudflare/shims/node-os.ts +14 -0
- package/cloudflare/shims/node-tty.ts +8 -0
- package/cloudflare/shims/node-zlib.ts +17 -0
- package/cloudflare/shims/noop.ts +26 -0
- package/cloudflare/shims/payment-vendor.ts +14 -0
- package/cloudflare/shims/querystring.ts +12 -0
- package/cloudflare/shims/queue.ts +585 -0
- package/cloudflare/shims/rolldown-runtime.ts +43 -0
- package/cloudflare/shims/sequelize-d1/datatypes.ts +24 -0
- package/cloudflare/shims/sequelize-d1/helpers.ts +46 -0
- package/cloudflare/shims/sequelize-d1/index.ts +34 -0
- package/cloudflare/shims/sequelize-d1/model.ts +1157 -0
- package/cloudflare/shims/sequelize-d1/operators.ts +293 -0
- package/cloudflare/shims/sequelize-d1/retry.ts +85 -0
- package/cloudflare/shims/sequelize-d1/sequelize-class.ts +119 -0
- package/cloudflare/shims/sequelize-d1/timing.ts +81 -0
- package/cloudflare/shims/sequelize-d1/types.ts +35 -0
- package/cloudflare/shims/stripe-cf.ts +29 -0
- package/cloudflare/shims/ws-lite.ts +103 -0
- package/cloudflare/shims/xss.ts +3 -0
- package/cloudflare/tests/shims/cron.spec.ts +210 -0
- package/cloudflare/tests/shims/queue-scheduled.spec.ts +186 -0
- package/cloudflare/vite.config.ts +162 -0
- package/cloudflare/worker.ts +1553 -0
- package/cloudflare/wrangler.json +63 -0
- package/cloudflare/wrangler.jsonc +69 -0
- package/cloudflare/wrangler.staging.json +66 -0
- package/cloudflare/wrangler.toml +28 -0
- package/jest.config.js +4 -12
- package/package.json +26 -22
- package/src/app.tsx +62 -4
- package/src/components/customer/link.tsx +9 -13
- package/src/components/customer/notification-preference.tsx +3 -2
- package/src/components/filter-toolbar.tsx +4 -0
- package/src/components/invoice/list.tsx +9 -1
- package/src/components/invoice-pdf/utils.ts +2 -1
- package/src/components/layout/admin.tsx +39 -5
- package/src/components/layout/user-cf.tsx +77 -0
- package/src/components/payment-intent/actions.tsx +23 -3
- package/src/components/safe-did-address.tsx +75 -0
- package/src/libs/patch-user-card.ts +25 -0
- package/src/libs/util.ts +5 -7
- package/src/pages/admin/billing/meter-events/index.tsx +4 -0
- package/src/pages/admin/customers/customers/detail.tsx +2 -2
- package/src/pages/admin/customers/customers/index.tsx +2 -2
- package/src/pages/admin/overview.tsx +3 -1
- package/src/pages/customer/subscription/detail.tsx +4 -4
- package/tsconfig.api.json +1 -6
- package/tsconfig.json +3 -4
- package/tsconfig.types.json +2 -1
- package/vite.config.ts +6 -1
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# Payment Kit Cloudflare Workers: 本地开发环境搭建与链上交互修复
|
|
2
|
+
|
|
3
|
+
## 总览
|
|
4
|
+
|
|
5
|
+
本次工作围绕两个目标展开:
|
|
6
|
+
|
|
7
|
+
1. **搭建 CF Workers 本地开发环境**,实现 payment-kit + blocklet-service 双 worker 协同运行,支持端到端支付测试。
|
|
8
|
+
2. **修复链上交互在 Workers 环境中的阻塞问题**,确保一次性支付和订阅支付正常完成。
|
|
9
|
+
|
|
10
|
+
### 核心发现与修复
|
|
11
|
+
|
|
12
|
+
| # | 问题 | 根因 | 修复 | 影响 |
|
|
13
|
+
|---|------|------|------|------|
|
|
14
|
+
| 1 | Worker hang:所有链上相关的 HTTP 请求永远 pending | axios 的 Node.js HTTP adapter 依赖 `node:http`(在 bundle 中被 shim 成空壳) | esbuild plugin 将 axios http adapter 重定向到 fetch adapter | 线上 + 本地 |
|
|
15
|
+
| 2 | 订阅支付 onConnect 超时(>8s) | delegation 链上查询串行累积延迟 6-10s | Promise.all / Promise.allSettled 并发化 | 线上 + 本地 |
|
|
16
|
+
| 3 | `encodeTransferV3Tx` 在 workerd 下 hang | `@ocap/client` 的 `getContext()` 内部 `setTimeout(resolve, 0)` 在 timer shim 下不触发 | 提前 `await client.getContext()` warm up 缓存 | 线上 + 本地 |
|
|
17
|
+
| 4 | 支付成功页前端崩溃 | vendor status API 返回 `vendors: null`,前端 `.map()` 报错 | null 防御 | 线上 + 本地 |
|
|
18
|
+
| 5 | webhook 发送在 CF Workers 下失败 | `componentApi` shim 缺少 `request()` 方法 | 补充 `request()` 实现 | 线上 + 本地 |
|
|
19
|
+
| 6 | 无迁移历史时每次订阅都查链 | `getMigratedFromList` 空结果不缓存(`length > 0` 才缓存) | 空数组也缓存,加 5 分钟 TTL | 线上 + 本地 |
|
|
20
|
+
|
|
21
|
+
### 改动文件一览
|
|
22
|
+
|
|
23
|
+
| 文件 | 类型 | 影响范围 |
|
|
24
|
+
|------|------|---------|
|
|
25
|
+
| `cloudflare/run-build.js` | 构建配置:新增 axiosFetchAdapterPlugin | 线上 + 本地 |
|
|
26
|
+
| `cloudflare/shims/axios-http-adapter.ts` | 新建:axios fetch adapter re-export | 线上 + 本地 |
|
|
27
|
+
| `cloudflare/shims/blocklet-sdk/component-api.ts` | 补充 `request()` 方法 | 线上 + 本地 |
|
|
28
|
+
| `api/src/libs/wallet-migration.ts` | 并发优化 + 缓存修复 + 自检 bug 修复 | 线上 + 本地 |
|
|
29
|
+
| `api/src/routes/connect/pay.ts` | getContext warm-up | 线上 + 本地 |
|
|
30
|
+
| `packages/payment-react-headless/src/checkout/hooks/useSubmit.ts` | vendors null 防御 | 线上 + 本地 |
|
|
31
|
+
| `packages/react/src/checkout-v2/views/success-view.tsx` | vendors null 防御 | 线上 + 本地 |
|
|
32
|
+
| `cloudflare/wrangler.dev.toml` | 本地开发配置(已 gitignore) | 仅本地 |
|
|
33
|
+
| `cloudflare/.dev.vars` | 本地密钥(已 gitignore) | 仅本地 |
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 一、本地开发环境搭建
|
|
38
|
+
|
|
39
|
+
### 1.1 架构
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Browser/Wallet
|
|
43
|
+
│
|
|
44
|
+
▼
|
|
45
|
+
┌─────────────────────────────────────────┐
|
|
46
|
+
│ cloudflared tunnel │
|
|
47
|
+
│ test-payment-tunnel.ofind.cn → :8787 │
|
|
48
|
+
└─────────────────┬───────────────────────┘
|
|
49
|
+
│
|
|
50
|
+
┌───────────┴───────────┐
|
|
51
|
+
▼ ▼
|
|
52
|
+
┌──────────────┐ ┌──────────────────┐
|
|
53
|
+
│ payment-kit │◄──►│ blocklet-service │
|
|
54
|
+
│ :8787 │ │ :8788 │
|
|
55
|
+
│ (wrangler) │ │ (wrangler) │
|
|
56
|
+
├──────────────┤ ├──────────────────┤
|
|
57
|
+
│ D1 (local) │ │ D1 (local) │
|
|
58
|
+
│ KV (local) │ │ settings 表 │
|
|
59
|
+
│ Assets │ │ users/sessions │
|
|
60
|
+
└──────────────┘ └──────────────────┘
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 1.2 启动步骤
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 1. 启动 blocklet-service(DID 认证)
|
|
67
|
+
cd did/services/blocklet-service
|
|
68
|
+
npx wrangler dev --port 8788 --local
|
|
69
|
+
|
|
70
|
+
# 2. 启动 payment-kit
|
|
71
|
+
cd payment-kit/blocklets/core
|
|
72
|
+
npx wrangler dev -c cloudflare/wrangler.dev.toml --local --port 8787
|
|
73
|
+
|
|
74
|
+
# 3. 启动 tunnel(可选,手机钱包测试需要)
|
|
75
|
+
cloudflared tunnel --config /tmp/cf-tunnel-config.yml --protocol http2 run did-dev
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 1.3 关键配置
|
|
79
|
+
|
|
80
|
+
**`cloudflare/wrangler.dev.toml`** — 本地开发专用:
|
|
81
|
+
- 无 `[build]` 段,直接使用预构建的 `dist/worker.js`
|
|
82
|
+
- D1/KV 使用本地模式(假 ID)
|
|
83
|
+
- `AUTH_SERVICE` service binding 连接本地 blocklet-service
|
|
84
|
+
- `APP_PID` 必须是从 `APP_SK` 推导出的合法 DID(否则前端 `getDIDMotifInfo` 崩溃,钱包 JWT 验签失败)
|
|
85
|
+
|
|
86
|
+
**身份一致性要求**:
|
|
87
|
+
- payment-kit 和 blocklet-service 共用同一个 `APP_SK`
|
|
88
|
+
- `APP_PID` = 从 SK 推导的 DID
|
|
89
|
+
- blocklet-service D1 的 `settings` 表中需注册该 DID 的 `app:sk`
|
|
90
|
+
- `__blocklet__.js` 返回的 `appPid`、`did`、`appPk` 三者必须一致
|
|
91
|
+
|
|
92
|
+
### 1.4 数据准备
|
|
93
|
+
|
|
94
|
+
从 staging D1 导出数据并导入本地:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# 导出
|
|
98
|
+
npx wrangler d1 export payment-kit-staging --remote -c cloudflare/wrangler.local.toml --output /tmp/staging-dump.sql
|
|
99
|
+
|
|
100
|
+
# 提取 INSERT 语句,按表导入
|
|
101
|
+
grep '^INSERT INTO.*products' /tmp/staging-dump.sql > /tmp/staging-products.sql
|
|
102
|
+
npx wrangler d1 execute payment-kit-local --local -c cloudflare/wrangler.dev.toml --file /tmp/staging-products.sql
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 二、axios fetch adapter 替换
|
|
108
|
+
|
|
109
|
+
### 2.1 问题
|
|
110
|
+
|
|
111
|
+
axios 在 Node.js 环境下默认使用 `http` adapter,依赖 `node:http` 和 `follow-redirects`。在 Worker bundle 中,这两个模块被 esbuild alias 替换为空壳 shim,导致 `http.request()` 永远不回调 → Worker hang → 500。
|
|
112
|
+
|
|
113
|
+
### 2.2 修复
|
|
114
|
+
|
|
115
|
+
在 `run-build.js` 中新增 esbuild plugin `axiosFetchAdapterPlugin`:
|
|
116
|
+
- 拦截 `axios/lib/adapters/http.js` 导入,重定向到 `fetch.js`
|
|
117
|
+
- 拦截 `follow-redirects` 和 `proxy-from-env`(仅被 http adapter 使用)指向 noop
|
|
118
|
+
|
|
119
|
+
### 2.3 风险评估(已自检)
|
|
120
|
+
|
|
121
|
+
**自检结论:无风险。** 全项目扫描确认所有 axios 调用仅使用 fetch 兼容选项(`timeout`、`baseURL`、`params`、`headers`)。
|
|
122
|
+
|
|
123
|
+
附带发现:exchange-rate providers 中 `error.code === 'ECONNABORTED'` 等 Node.js 错误码检查,fetch adapter 不产生这些错误码,会 fallback 到通用 branch。不影响功能,仅错误信息不够精确。
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 三、delegation 链上查询并发优化
|
|
128
|
+
|
|
129
|
+
### 3.1 问题
|
|
130
|
+
|
|
131
|
+
`getDelegationAddressWithFallback` 串行执行多次链上 RPC,总延迟 6-10s,超过钱包 8s 超时。
|
|
132
|
+
|
|
133
|
+
### 3.2 修复
|
|
134
|
+
|
|
135
|
+
- Step 2(getDelegateState)与 Step 3(getMigratedFromList)改为 `Promise.all` 并发
|
|
136
|
+
- Step 3 内部多个 migratedFrom 地址查询改为 `Promise.allSettled` 并发
|
|
137
|
+
- 总延迟从 ~8s 降到 ~2-4s
|
|
138
|
+
|
|
139
|
+
### 3.3 自检发现与修复
|
|
140
|
+
|
|
141
|
+
| 问题 | 影响 | 修复 |
|
|
142
|
+
|------|------|------|
|
|
143
|
+
| `currentStateResult.error` 被无条件赋值覆盖 | 失败时错误信息丢失 | 赋值时保留 `error` 字段 |
|
|
144
|
+
| `results.indexOf(result)` 获取索引 | O(n) 且不符合惯例 | 改为 `for (let i = 0; ...)` |
|
|
145
|
+
| `getMigratedFromList` 空结果不缓存 | 最常见场景每次都查链 | 空数组也缓存,加 5 分钟 TTL 防止迁移后缓存过期 |
|
|
146
|
+
|
|
147
|
+
### 3.4 风险评估(已自检)
|
|
148
|
+
|
|
149
|
+
| 风险项 | 自检结果 |
|
|
150
|
+
|--------|---------|
|
|
151
|
+
| 短路逻辑弱化(step 2 命中时 step 3 已发出) | 影响极小,仅多一次 getAccountState |
|
|
152
|
+
| 链节点并发压力 | migratedFrom 典型 0-3 个,无需 pLimit |
|
|
153
|
+
| 错误传播变化 | 语义与原来一致(原来也 catch 继续) |
|
|
154
|
+
| 空缓存 TTL 过期后重新查链 | 5 分钟刷新一次,平衡了性能和数据新鲜度 |
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 四、getContext warm-up
|
|
159
|
+
|
|
160
|
+
在 `pay.ts` 的 `onAuth` 中提前 `await client.getContext()` 让缓存 ready,避免 `encodeTransferV3Tx` 内部的 `setTimeout(resolve, 0)` 在 workerd timer shim 下 hang。
|
|
161
|
+
|
|
162
|
+
风险:几乎无。有内部缓存,通常在 `onConnect` 阶段已 warm up。
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## 五、componentApi.request() shim 补充
|
|
167
|
+
|
|
168
|
+
`queues/webhook.ts` 调用 `componentApi.request()` 发送 webhook 通知,但原 shim 只实现了 `post()` 和 `get()`。补充 `request()` 方法,支持自定义 method、headers、timeout(通过 AbortController)。
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 六、前端 vendors null 防御
|
|
173
|
+
|
|
174
|
+
- `useSubmit.ts`:确保 `vendors` 始终为数组
|
|
175
|
+
- `success-view.tsx`:`.map()` 前加 `|| []` 防御
|
|
176
|
+
|
|
177
|
+
无风险,纯防御性代码。
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 七、自检覆盖范围
|
|
182
|
+
|
|
183
|
+
### 已完成的自检
|
|
184
|
+
|
|
185
|
+
| 检查项 | 方法 | 结论 |
|
|
186
|
+
|--------|------|------|
|
|
187
|
+
| axios fetch adapter 兼容性 | 全项目 grep 所有 axios 调用和选项 | **无风险**:无 Node.js 特有选项使用 |
|
|
188
|
+
| migratedFrom 并发数量 | 源码分析 + 测试数据 | **低风险**:典型 0-3 个 |
|
|
189
|
+
| Promise.allSettled 索引正确性 | 代码审查 | **已修复**:`indexOf` 改为直接索引 |
|
|
190
|
+
| currentStateResult.error 丢失 | 代码审查 | **已修复**:保留 error 字段 |
|
|
191
|
+
| 空缓存无 TTL | 逻辑分析 | **已修复**:加 5 分钟 TTL |
|
|
192
|
+
| componentApi shim 完整性 | grep 所有 componentApi 方法调用 | **已修复**:补充 `request()` |
|
|
193
|
+
|
|
194
|
+
### 需要仕军 review 的内容
|
|
195
|
+
|
|
196
|
+
以下改动涉及链上交互的核心逻辑,建议仕军重点审查:
|
|
197
|
+
|
|
198
|
+
#### 1. `wallet-migration.ts` — 并发化改动的业务正确性
|
|
199
|
+
|
|
200
|
+
**关注点**:
|
|
201
|
+
- 原来串行查询有隐含的优先级(stored → current → migrated),并发后 step 2 和 step 3 同时发出。如果 `current` 地址命中,`getMigratedFromList` 的链上请求已经发出但结果会被丢弃。确认这是否有副作用。
|
|
202
|
+
- `Promise.allSettled` 返回的结果顺序是否保证和 `migratedFrom` 输入顺序一致(根据 ES 规范是保证的,但建议确认)。
|
|
203
|
+
- 空缓存 TTL 5 分钟是否合理 — 应用迁移后需要等最多 5 分钟才能发现新的 migratedFrom。
|
|
204
|
+
|
|
205
|
+
#### 2. `pay.ts` — getContext warm-up 的必要性
|
|
206
|
+
|
|
207
|
+
**关注点**:
|
|
208
|
+
- `getContext()` 内部的 `setTimeout(resolve, 0)` 是 `@ocap/client` 的实现细节。如果上游升级移除了这个 setTimeout,warm-up 就变成冗余代码。建议确认是否有更根本的方式处理 timer shim 和 `getContext` 的交互。
|
|
209
|
+
- 线上 Cloudflare Workers(非 wrangler dev local)是否也受 `setTimeout(resolve, 0)` 影响,还是仅本地 workerd 有问题。
|
|
210
|
+
|
|
211
|
+
#### 3. axios fetch adapter — 对 exchange-rate providers 的影响
|
|
212
|
+
|
|
213
|
+
**关注点**:
|
|
214
|
+
- `coingecko-provider.ts`、`coinmarketcap-provider.ts`、`token-data-provider.ts` 中的错误处理依赖 `error.code === 'ECONNABORTED'` 等 Node.js 错误码。fetch adapter 下这些分支永远不会触发,错误会 fallback 到通用处理。确认通用处理的行为(重试策略、降级逻辑)是否足够。
|
|
215
|
+
|
|
216
|
+
#### 4. componentApi.request() shim — 与原始实现的差异
|
|
217
|
+
|
|
218
|
+
**关注点**:
|
|
219
|
+
- 原始 `@blocklet/sdk` 的 `componentApi` 会在请求头中自动添加签名(`x-component-sig` 等),shim 版本没有签名逻辑。webhook 接收方如果验证签名,请求会被拒绝。
|
|
220
|
+
- shim 的 `request()` 使用 `AbortController` 实现 timeout,与原始 axios 的 timeout 行为可能有细微差异(如连接超时 vs 响应超时)。
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 八、验证结果
|
|
225
|
+
|
|
226
|
+
| 场景 | 本地环境 | staging 线上 |
|
|
227
|
+
|------|---------|-------------|
|
|
228
|
+
| 一次性支付(链上) | ✅ | ✅ |
|
|
229
|
+
| 订阅支付(delegation + stake) | ✅ | ✅(手机钱包) |
|
|
230
|
+
| 前端 checkout 页面 | ✅ | ✅ |
|
|
231
|
+
| DID Connect 认证流程 | ✅ | ✅ |
|
|
232
|
+
| `__blocklet__.js` 身份一致性 | ✅ | ✅ |
|
|
233
|
+
|
|
234
|
+
Web 钱包扩展有少量非阻塞报错(EVM 余额查询超时、内部队列暂停),属于钱包端问题,不影响支付流程。
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 九、排查过程记录
|
|
239
|
+
|
|
240
|
+
### 使用的排查手段
|
|
241
|
+
|
|
242
|
+
| 手段 | 用途 | 效果 |
|
|
243
|
+
|------|------|------|
|
|
244
|
+
| `vite build --minify false` | 让前端错误堆栈可读 | 从 `cc`/`z7` 定位到 `getDIDMotifInfo`/`convert.hex.rgb` |
|
|
245
|
+
| `console.log` 关键路径插桩 | 确定 hang 的精确位置 | 定位到 `encodeTransferV3Tx` |
|
|
246
|
+
| `grep` bundle 分析 | 检查 `node:http`/`follow-redirects` | 确认 axios 用了错误的 adapter |
|
|
247
|
+
| D1 dev endpoint 查数据 | 检查 payment intent 状态 | 发现 `processing` 脏状态 |
|
|
248
|
+
| JWT base64 解码 | 检查身份字段 | 发现 appPid/appPk/did 不一致 |
|
|
249
|
+
| `@ocap/client` 源码阅读 | 追溯调用链 | 找到 `getContext` → `setTimeout` 根因 |
|
|
250
|
+
| wrangler 请求日志时序分析 | 分析并发模式 | 理解 workerd 并发限制 |
|
|
251
|
+
| 全项目 axios 调用扫描 | 自检 fetch adapter 兼容性 | 确认无 Node.js 特有选项使用 |
|
|
252
|
+
|
|
253
|
+
### 问题解决时间线
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
环境搭建
|
|
257
|
+
├─ wrangler.dev.toml + D1 migration + staging 数据导入
|
|
258
|
+
├─ blocklet-service instance 注册
|
|
259
|
+
└─ cloudflared tunnel 建立
|
|
260
|
+
|
|
261
|
+
前端报错 "null is not iterable"
|
|
262
|
+
└─ 根因:APP_PID 不是合法 DID → getDIDMotifInfo 返回 null
|
|
263
|
+
|
|
264
|
+
JWT 验签失败
|
|
265
|
+
└─ 根因:appPk(blocklet-service) ≠ APP_SK(payment-kit) → 复用同一 SK
|
|
266
|
+
|
|
267
|
+
Worker hang (一次性支付)
|
|
268
|
+
├─ 初始判断:链上 RPC 超时 → 加 skip 逻辑(错误方向,已撤回)
|
|
269
|
+
├─ 最终根因:axios http adapter 被 shim 成空壳
|
|
270
|
+
└─ 修复:esbuild plugin 重定向到 fetch adapter
|
|
271
|
+
|
|
272
|
+
Worker hang (订阅支付)
|
|
273
|
+
├─ 表现:onConnect 阶段 10s 超时
|
|
274
|
+
├─ 根因:delegation 查询串行 6-10s
|
|
275
|
+
└─ 修复:Promise.all / Promise.allSettled 并发
|
|
276
|
+
|
|
277
|
+
自检
|
|
278
|
+
├─ axios 兼容性:全项目确认无风险
|
|
279
|
+
├─ migratedFrom 数量:确认典型 0-3 个
|
|
280
|
+
├─ Bug: currentStateResult.error 被覆盖 → 已修复
|
|
281
|
+
├─ Bug: results.indexOf(result) 不安全 → 已修复
|
|
282
|
+
├─ 优化: 空 migratedFrom 不缓存 → 已修复,加 TTL
|
|
283
|
+
└─ Bug: componentApi.request() 缺失 → 已修复
|
|
284
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Payment Kit 清理任务清单(2026-05)
|
|
2
|
+
|
|
3
|
+
> 2026-04-13 与叶小芳走查 + 2026-05-14 CF 迁移 staging 测试发现的问题汇总。每一条都对应一个 GitHub issue,做完打勾。
|
|
4
|
+
|
|
5
|
+
## 🔴 Bug
|
|
6
|
+
|
|
7
|
+
- [x] [#1357](https://github.com/blocklet/payment-kit/issues/1357) Customer Search 选择器输入 'a'/'w' 等字符触发下拉关闭 — TextField 加 `onKeyDown stopPropagation`,team `1ae68ff6` / 个人 `690c1ef6`
|
|
8
|
+
- [x] [#1344](https://github.com/blocklet/payment-kit/issues/1344) **P0** Off-chain credits 退款后 grant 未回滚 — 已修复 commit `6b96a8b9`,已部署
|
|
9
|
+
- [x] [#1349](https://github.com/blocklet/payment-kit/issues/1349) CF staging GET /api/tax-rates 500 — 已修复 commit `6b96a8b9`(同上),已部署
|
|
10
|
+
- [x] [#1345](https://github.com/blocklet/payment-kit/issues/1345) 退款 UI "最大可退"金额四舍五入 — 已修复(floor 替代 round),部署 team `f3464352` / 个人 `e2584c83`
|
|
11
|
+
- [x] [#1351](https://github.com/blocklet/payment-kit/issues/1351) CF Workers runtime hang 偶发 — 已部分缓解(getTokenLimits/getTokenRequirements 并行化)team `530b3bec` / 个人 `c5f2ee68`;监控冷启动 hang 是否还出现
|
|
12
|
+
- [x] [#1356](https://github.com/blocklet/payment-kit/issues/1356) 一次性支付显示成功但页面展示失败 — parseChainError 加 `GAS_PAYER_NOT_ON_CHAIN` 分支,team `1c17d48e` / 个人 `db0d13fd`;待用户复现验证
|
|
13
|
+
|
|
14
|
+
## 🟠 功能缺口
|
|
15
|
+
|
|
16
|
+
- [ ] [#1358](https://github.com/blocklet/payment-kit/issues/1358) 欠费账单允许切换支付方式 — P2
|
|
17
|
+
- [ ] [#1359](https://github.com/blocklet/payment-kit/issues/1359) 滑点配置展示"最坏情况下要付多少 TBA" — P3
|
|
18
|
+
- [ ] [#1360](https://github.com/blocklet/payment-kit/issues/1360) 滑点超出后主动告警通知 — P3
|
|
19
|
+
|
|
20
|
+
## 🟡 历史代码清理(CF Workers bundle 瘦身)
|
|
21
|
+
|
|
22
|
+
- [ ] [#1361](https://github.com/blocklet/payment-kit/issues/1361) 砍掉通行证 / Passport 功能
|
|
23
|
+
- [ ] [#1362](https://github.com/blocklet/payment-kit/issues/1362) 评估并砍掉定价表 (Pricing Table)
|
|
24
|
+
- [ ] [#1363](https://github.com/blocklet/payment-kit/issues/1363) 砍掉计量服务 (Metering Service)
|
|
25
|
+
- [ ] [#1364](https://github.com/blocklet/payment-kit/issues/1364) 砍掉 DID Names 批量订阅 (group subscription)
|
|
26
|
+
- [ ] [#1365](https://github.com/blocklet/payment-kit/issues/1365) 评估 setup 支付类型是否还需要
|
|
27
|
+
|
|
28
|
+
## ⚠️ 产品决策类
|
|
29
|
+
|
|
30
|
+
- [ ] [#1366](https://github.com/blocklet/payment-kit/issues/1366) 税费组件半成品:做完含税计算或砍掉
|
|
31
|
+
|
|
32
|
+
## 🧹 运维 / 数据清理
|
|
33
|
+
|
|
34
|
+
- [ ] [#1367](https://github.com/blocklet/payment-kit/issues/1367) 清理 staging 上 0 ABT 旧版按量订阅僵尸数据
|
|
35
|
+
|
|
36
|
+
## 🟢 文档
|
|
37
|
+
|
|
38
|
+
- [ ] [#1368](https://github.com/blocklet/payment-kit/issues/1368) Payment Kit 数据表 ER 关系图
|
|
39
|
+
- [ ] [#1369](https://github.com/blocklet/payment-kit/issues/1369) 订阅变更流程 (Change Plan/Currency/Payer) 详细文档
|
|
40
|
+
- [ ] [#1370](https://github.com/blocklet/payment-kit/issues/1370) 各业务方 past_due 状态处理规则文档
|
|
41
|
+
- [ ] [#1371](https://github.com/blocklet/payment-kit/issues/1371) Gas-payer JWT / Stake-for-gas 机制文档
|
|
42
|
+
|
|
43
|
+
## ✅ 已完成 / 已关闭(追溯)
|
|
44
|
+
|
|
45
|
+
- ✅ 钱包侧 hash mismatch bug(ArcWallet Android `AuthPresenter.kt:1716`)—— 钱包团队已修
|
|
46
|
+
- ✅ Payment Kit `getGasPayerExtra` 临时 merchant 自签 fix —— 已 revert (`f6aaf7f6`),钱包修好后不需要
|
|
47
|
+
- ✅ [#1178](https://github.com/blocklet/payment-kit/issues/1178) 快捷支付未考虑 gas 资金 — 关闭(链上机制设计正确,钱包侧已修,详见关闭评论)
|
|
48
|
+
|
|
49
|
+
## 推荐处理顺序
|
|
50
|
+
|
|
51
|
+
1. **P0**:#1344(钱出错)
|
|
52
|
+
2. **CF 阻塞性 P1**:#1349、#1345、#1351
|
|
53
|
+
3. **看起来好修的 P2**:#1357(搜索框)、#1358(切支付方式)
|
|
54
|
+
4. **清理减包体**(CF 包大小敏感):#1361 → #1362 → #1363 → #1364 → #1365 顺序做
|
|
55
|
+
5. **产品决策**:#1366(税费),决定后顺手关 #1349 如果决定砍税费
|
|
56
|
+
6. **文档** + 运维数据:#1367、#1368、#1369、#1370、#1371
|
|
57
|
+
|
|
58
|
+
## 维护说明
|
|
59
|
+
|
|
60
|
+
- 做完一项把 `[ ]` 改成 `[x]` 并附 commit / PR 链接
|
|
61
|
+
- 新发现的问题先建 GitHub issue 再加到本文件
|
|
62
|
+
- 本文件存活到所有上面任务关闭,然后可删
|