docs(home): record slow-network acceptance
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# 印度占星 Skill 更新日志
|
||||
|
||||
## 2026-09-24 — 慢网首页与账户点数首开优化(待 staging 验收)
|
||||
|
||||
- 首页取消 8 秒硬超时:账户 / 会话、模型与咨询状态并行准备,20 秒后才进入全屏错误屏;错误屏重试局部重跑,不整页刷新,模型失败不揭幕半成品。
|
||||
- 账户与点数预取动态分包,未到时显示静态句;套餐同会话缓存 60 秒并后台刷新,移除挂载时重复 `/api/account`,支付/兑换使用接口返回余额广播同步。
|
||||
- Skill 版本不 bump。自动化定向合同 65/65 通过;浏览器、build、部署和 staging health 尚待独立验收。
|
||||
|
||||
|
||||
## 2026-09-24 — 星盘等待有盘位,失败有出口(本地实现,待验收)
|
||||
|
||||
- 主盘、分盘与西洋盘未到时显示空盘骨架轻缓呼吸;系统减弱动态效果时静止。其它页面和大运 / 七政表格不增加骨架。
|
||||
|
||||
@@ -13560,6 +13560,34 @@
|
||||
- 复发自:BUG-715/723 的失败分档未覆盖按需层投影与组件出口;旧测试仅验主盘错误和端点不可用说明,未串联真实 busy 层响应到 hook。
|
||||
- 修复版本:`1420471a`(staging 已部署、health 核对一致)
|
||||
|
||||
## BUG-1021 | 慢网首页半揭幕,模型与账户状态脱节
|
||||
|
||||
- 状态:resolved(本地 Windows/Node 20 定向合同与 TypeScript 验证通过;浏览器 Slow 3G、staging health 与部署证据待产品/协调方完成)
|
||||
- 首次发现 / 最近更新:2026-09-24。
|
||||
- 影响面:首页账户、会话、模型目录、咨询状态 bootstrap 与重试。
|
||||
- 现象 / 触发:Slow 3G 强刷首页,原 8 秒串行预算先显示云端超时;SessionListProvider 后到仍写账户/会话,页面可能揭幕为模型不可用、发送禁用并重新询问称呼的半成品。
|
||||
- 根因:Home 自有 8 秒 AbortController 与 SessionListProvider 独立请求脱节;模型目录失败只写 composer 提示却仍允许账户提交;渲染门未要求模型目录存在。
|
||||
- 修复:引入 20 秒 `HOME_BOOTSTRAP_SLOW_MS`;模型、咨询状态与 provider 并行启动;必要数据齐全前统一等待,模型/必要请求失败保持全屏错误;重试取消旧请求、reload provider 并局部重跑;provider 使用可重入读取和旧 generation/controller 防护;首屏 ES5 fallback 调为 25 秒。
|
||||
- 验证:`tsc --noEmit` 通过;首页与 fallback 定向合同通过;完整 lint 有 0 error、既有 warnings;浏览器与部署验收未在本地宣称通过。
|
||||
- 防复发:保留一次等待一次揭幕、错误屏要求 `account` 与 `modelCatalog`,禁止 React 错误屏使用 `location.reload()`;provider 旧请求不得提交状态。
|
||||
- 相关记录:BUG-479、BUG-927、BUG-936;`TASK-home-slow-network-20260924.md`。
|
||||
- 复发自:无;BUG-927 引入的 provider/Home 时序脱节首次在本单补齐门控。
|
||||
- 修复版本:`659bd9600`(待 staging 推送与部署核对)。
|
||||
|
||||
## BUG-1022 | 账户与点数首次打开慢且离线预取会误触发刷新
|
||||
|
||||
- 状态:resolved(本地 Node 20 定向合同通过;浏览器与 staging 验收待完成)
|
||||
- 首次发现 / 最近更新:2026-09-24。
|
||||
- 影响面:账户菜单、BillingPanel 动态分包、套餐接口与支付/兑换余额同步。
|
||||
- 现象 / 触发:首次打开账户与点数需等待懒加载 chunk 和套餐请求;面板挂载还会重复请求完整 `/api/account`;指针悬停离线时动态 import reject 可能被全局 stale-client recovery 当作 ChunkLoadError 并整页刷新。
|
||||
- 根因:账单 chunk 无预取/静态占位;套餐零缓存;挂载账户请求结果被 Home 传入账户覆盖;prefetch reject 未隔离。
|
||||
- 修复:账户菜单 pointer enter/down 预取 chunk 和套餐;chunk 未到时显示静态占位;套餐结果模块缓存 60 秒并后台刷新;独立 route 查询并行;删除挂载 `/api/account`,兑换和支付直接用响应 `credits` 通过既有共享事件同步;prefetch 显式 catch 隔离失败。
|
||||
- 验证:账单、membership、epay、首页 bootstrap/fallback 定向合同共 65/65;TypeScript 通过;定向 lint 通过;完整 lint 0 error、既有 warnings;浏览器/部署验收待完成。
|
||||
- 防复发:合同锁定无 `/api/account`、响应 credits 同步和 prefetch catch;动态 import 预取失败不得冒泡到全局刷新逻辑。
|
||||
- 相关记录:BUG-479、BUG-1021、`TASK-home-slow-network-20260924.md`。
|
||||
- 复发自:BUG-554(账户与点数离开首页的旧入口已修复);本单是性能与慢网回归,不改变设置弹窗入口。
|
||||
- 修复版本:`1fbe14995`、`6a097b6a3`(待 staging 推送与部署核对)。
|
||||
|
||||
## BUG-1020 | CRLF 普通报告下载保留图盘 JSON 围栏
|
||||
|
||||
- 状态:investigating(产品 2026-09-24 批准 D5 有限例外 D14,修复单待领取;未修复前不得标 resolved)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# PROGRESS · 慢网首页半揭幕 + 账户与点数打开慢(2026-09-24)
|
||||
|
||||
## 当前状态
|
||||
|
||||
- 实际 worktree:`G:\Ferti\Jyotisha\.claude\worktrees\agent-aa9a862be5b171b9b`
|
||||
- 分支:`codex/home-slow-network-20260924`
|
||||
- 基线:`origin/staging` `edc9c22c3`
|
||||
- 当前实现提交:`1fbe14995`、`659bd9600`、`6a097b6a3`;本记录及最终验收修订尚未提交。
|
||||
- 第二单、第三单未开始,按任务书串行依赖暂停。
|
||||
|
||||
## 实施
|
||||
|
||||
### T1 首页启动
|
||||
|
||||
- 新增 `HOME_BOOTSTRAP_SLOW_MS = 20_000`;删除原 8 秒硬超时语义。
|
||||
- `/api/models`、咨询状态和 SessionListProvider 启动读取并行;模型或必要 bootstrap 请求失败时在 commit 前进入全屏错误状态,不揭幕半成品首页。
|
||||
- React 错误屏「重试」取消上一轮、reload provider 读取并局部重跑,不调用 `location.reload()`。
|
||||
- SessionListProvider 增加可重入 reload、AbortController 替换和旧请求提交保护。
|
||||
- 首屏 ES5 fallback 调为 25 秒,仍保留六类失败分类;只有 bundle 没运行的首屏 fallback 按钮才允许用户点击整页 reload。
|
||||
|
||||
### T2 账户与点数
|
||||
|
||||
- BillingPanel 动态分包使用静态占位「账户信息还没拿到。」;账户菜单 pointer enter/down 预取 chunk 和套餐。
|
||||
- 移除 `use-billing-panel` 挂载时完整 `/api/account` 请求;兑换成功使用兑换响应 `credits`,支付成功使用 status 响应 `credits`,均通过既有共享余额事件同步,不新增账户请求。
|
||||
- 套餐结果模块级缓存 60 秒,过期返回旧值并后台刷新;套餐 route 的 feature flags 与商品读取并行,权益仍在 product IDs 就绪后读取。
|
||||
- 预取动态 chunk 的失败显式 catch 隔离,不让离线 hover 预取触发全局 stale-client recovery reload。
|
||||
|
||||
## 三栏断言调整
|
||||
|
||||
| 文件 | 原值 | 新值 | 原因 |
|
||||
| --- | --- | --- | --- |
|
||||
| `frontend/tests/membership-navigation-contract.test.ts` | 挂载断言 `Promise.allSettled([fetchAccountData(), fetchPackages()])`,认证跳转计数 4 | 仅断言套餐加载、无 `fetchAccountData`/`/api/account`;认证跳转计数 3 | T2 删除无用挂载账户请求,保留订单、兑换、支付状态的 401 硬跳转 |
|
||||
| `frontend/tests/epay-settings.test.ts` | 直接断言 hook fetch `/api/payment/packages`、`payload.enabled` 和旧 `setPaymentEnabled(true)` | 断言 hook 使用 `fetchPaymentPackages`,缓存模块发起请求并规范化 enabled | 网络请求迁移到 60 秒共享缓存,支付开关行为不变 |
|
||||
| `frontend/tests/billing-panel.test.ts` | 兑换/支付后再次 `fetchAccountData()`;预取无失败处理 | 断言使用响应 credits 广播余额,预取 promise catch 隔离 | 删除重复账户查询但保留成功后的余额同步,避免离线预取未处理 rejection |
|
||||
| `frontend/tests/first-paint-fallback-contract.test.ts` | 兜底晚于 8 秒 + 4 秒 prepare | 兜底晚于 20 秒慢网阈值并留余量 | 新首页 slow-network budget 为 20 秒 |
|
||||
|
||||
## 验证结果
|
||||
|
||||
已通过:
|
||||
|
||||
```text
|
||||
./node_modules/.bin/tsc --noEmit exit 0
|
||||
./node_modules/.bin/eslint src/hooks/use-billing-panel.ts \
|
||||
src/lib/session-list-context.tsx tests/epay-settings.test.ts exit 0
|
||||
./node_modules/.bin/tsx --test \
|
||||
tests/membership-navigation-contract.test.ts \
|
||||
tests/billing-panel.test.ts tests/epay-settings.test.ts \
|
||||
tests/home-bootstrap-reveal.test.ts \
|
||||
tests/first-paint-fallback-contract.test.ts 65 pass / 0 fail
|
||||
```
|
||||
|
||||
全量 `npm run lint` 已执行:0 error、121 warnings;warnings 为仓库既有问题,本轮新增的 `epay-settings` 未使用变量 warning 已移除。全量 `npm test`、`npm run build`、浏览器 Slow 3G / Offline 真人验收仍需最终执行/记录。
|
||||
|
||||
## 环境缺口
|
||||
|
||||
- 本轮未读取或提交任何真实隐私资料、凭据、Cookie、JWT 或模型密钥。
|
||||
- 本地 Windows worktree 可完成 TypeScript、定向合同和定向 lint;尚未有 Chrome 登录态,真人 Slow 3G / Offline、动态 chunk 网络行为无法在本地声明通过。
|
||||
- 尚未执行 build、Static/gzip 对比、Docker/Linux volume 保真路径和 staging health;不能据此声称部署或 staging 已验收。
|
||||
- 未 push;Gitea 认证 token 当前不可用,需协调方恢复既定认证后再按 `status → fetch --prune → 同步 origin/staging → push` 流程交付。
|
||||
|
||||
## 后续
|
||||
|
||||
1. 独立复核本记录、BUG_HISTORY 和定向测试。
|
||||
2. 完成全量前端测试、build 与可用的静态/gzip 对比;将失败名单与基线逐项记录。
|
||||
3. 协调推送前先 `git status -sb`、`git fetch origin --prune`,同步最新 `origin/staging`,确认无共享工作树改动后再推送本单。
|
||||
4. staging 验收通过后才领取 `TASK-chart-ephemeris-fixes-20260924.md`。
|
||||
@@ -0,0 +1,41 @@
|
||||
# 慢网首页与账户点数真人验收清单(2026-09-24)
|
||||
|
||||
> 仅使用受控测试账号和虚构资料;不要记录姓名、出生资料、邮箱、Cookie、JWT 或完整会话内容。
|
||||
|
||||
## 自动化前置
|
||||
|
||||
- [ ] `tsc --noEmit` 通过。
|
||||
- [ ] `npm run lint` 结果与进度记录一致;warnings 不得新增。
|
||||
- [ ] 定向合同测试 65/65 通过。
|
||||
- [ ] `npm test`、`npm run build`、`/` Static 与首屏 gzip 对比完成。
|
||||
|
||||
## Chrome Slow 3G 首页
|
||||
|
||||
1. 打开 Chrome DevTools Network,选择 Slow 3G,清空缓存并强刷 `/`。
|
||||
2. 确认揭幕后只发生一次等待:未到齐前只有既有首页轨道环;账户、会话、模型和必要 bootstrap 数据齐后一次揭幕。
|
||||
3. 确认揭幕后没有 spinner、骨架或「正在加载」;模型可选择,发送按钮可用,页面不再次询问已存在的称呼。
|
||||
4. 在 provider 较慢、模型先到和模型较慢两种顺序各重复一次;确认没有首页+错误条的半揭幕。
|
||||
|
||||
## 模型失败与慢网错误屏
|
||||
|
||||
1. 用受控网络规则让 `/api/models` 失败、但账户/会话成功。
|
||||
2. 确认首页不揭幕,显示「暂时无法进入 Jyotisha」错误屏,不出现模型不可用的半成品。
|
||||
3. 让请求持续超过 20 秒;确认显示现有全屏错误屏。
|
||||
4. 恢复网络后点击「重试」,确认只重跑请求并进入首页;在 DevTools 断点或脚本中确认没有调用 `location.reload()`。
|
||||
|
||||
## 账户与点数
|
||||
|
||||
1. 正常打开账户菜单,将指针移到「账户与点数」,观察动态 chunk 和 `/api/payment/packages` 预取。
|
||||
2. 首次打开确认 chunk 未到时显示静态句「账户信息还没拿到。」,不显示 spinner;套餐接口只请求一次。
|
||||
3. 关闭后第二次打开,确认 60 秒内套餐立即显示,网络请求为 0 或后台刷新一次。
|
||||
4. 兑换成功后确认余额通过共享事件更新;支付成功轮询后确认余额更新;Network 中不出现由面板挂载触发的额外 `/api/account`。
|
||||
5. 在离线状态把指针移到「账户与点数」,确认预取失败不触发整页自动刷新;恢复网络后由用户重新打开或重试。
|
||||
|
||||
## 结果记录
|
||||
|
||||
- 浏览器 / 版本:
|
||||
- 账号类型(不要写账号标识):
|
||||
- 测试时间:
|
||||
- 通过项:
|
||||
- 未通过项与脱敏截图路径:
|
||||
- 环境缺口:无 Chrome、无受控账号或无法模拟网络时填写,不得写成通过。
|
||||
+3
-3
@@ -693,13 +693,13 @@ Agent 的 live 标记只有 `InlineSpinner` 一种。曾经并存的 canvas 小
|
||||
|
||||
校正面的所有等待复用行内等待:进入前的 hydration 在揭幕之前完成,进入后唯一的等待形态是时间线 live 行(含「正在准备下一个问题…」这一条独立 live 行)。区间交付卡只挂在最新那条采用旁白下面,不得留在更早的采集/区分题下。有未答的采集或选择题时卡仍在,「更像这个」置灰并写「先答完上面这道,再选时间」,不得整卡消失。卡上至多三列并排,相同性格句只写一次,点「更像这个」即采用该列分钟,按钮显示「正在采用…」或「已采用」。采用过程中整张卡留在原处,不得因 `busy` 卸掉。采用后前事核对结束走 `verified_idle`:一行收尾文案跟在卡片下面、与助手列对齐,没有 live 行、没有重载、没有采用状态条。卡片与右栏细则见 §11、§12。
|
||||
|
||||
首页只揭幕一次。揭幕前的加载屏分两阶段:先取账户、模型目录与会话列表,再并行取今日星语与校正入口摘要,并预热校正分包;全部就绪或 4 秒预算到期(`BOOTSTRAP_PREPARE_TIMEOUT_MS`)才揭幕。揭幕后不得再出现任何阻塞等待或组件级 spinner:今日星语未到显示静态文案「今天的星语还没写出来。」(不带 `aria-busy`),校正卡用无摘要文案,内容到达后静默替换。登录后的空首页只剩问候语、今日星语卡、生时校正卡和输入框,没有主题卡。切换到消息尚未缓存的会话时消息区留白并只给 `sr-only` 文案,不转圈;揭幕后按侧栏顺序后台预取最近 5 条会话(`SESSION_PREFETCH_COUNT`)让常见切换零等待。轨道环消失后不得再换一套动效继续等。
|
||||
首页只揭幕一次。揭幕前的加载屏先并行取账户 / 会话、模型目录和咨询状态,再等待 lookup、会话详情等依赖数据全部到齐;不设 8 秒硬超时,超过 `HOME_BOOTSTRAP_SLOW_MS = 20_000` 才进入现有全屏错误屏。错误屏的「重试」只取消旧请求、重载 provider 并局部重跑 bootstrap,不调用 `location.reload()`。揭幕后不得再出现任何阻塞等待或组件级 spinner:今日星语未到显示静态文案「今天的星语还没写出来。」(不带 `aria-busy`),校正卡用无摘要文案,内容到达后静默替换。登录后的空首页只剩问候语、今日星语卡、生时校正卡和输入框,没有主题卡。切换到消息尚未缓存的会话时消息区留白并只给 `sr-only` 文案,不转圈;揭幕后按侧栏顺序后台预取最近 5 条会话(`SESSION_PREFETCH_COUNT`)让常见切换零等待。轨道环消失后不得再换一套动效继续等。
|
||||
|
||||
### 首屏死屏兜底
|
||||
|
||||
首页揭幕前的轨道环是纯 CSS。客户端 bundle 没执行、关键 chunk 没加载或没解析成功时,8 秒的云端超时和 4 秒揭幕都不会发生,轨道会一直转。
|
||||
首页揭幕前的轨道环是纯 CSS。客户端 bundle 没执行、关键 chunk 没加载或没解析成功时,应用层 20 秒云端慢网错误屏不会发生,轨道会一直转,交给独立的首屏兜底脚本处理。
|
||||
|
||||
根 layout 里有一段与 bundle 无关的内联经典脚本。它只在同时满足这两条时换掉 `.app-loading-content`:页面上仍有 `.app-loading`,且 `<html data-hydrated>` 不是 `"1"`。时限是 13 秒,大于载入账户的 8 秒加上准备阶段的 4 秒,正常揭幕不会闪出这一屏。应用揭幕(`hydrated` 为真)后,现有首页装配 hook 写下 `data-hydrated="1"`。
|
||||
根 layout 里有一段与 bundle 无关的内联经典脚本。它只在同时满足这两条时换掉 `.app-loading-content`:页面上仍有 `.app-loading`,且 `<html data-hydrated>` 不是 `"1"`。时限是 25 秒,大于应用层 20 秒慢网阈值并留出余量,正常揭幕不会闪出这一屏。应用揭幕(`hydrated` 为真)后,现有首页装配 hook 写下 `data-hydrated="1"`。
|
||||
|
||||
出现时复用 `.app-loading-error` 的卡片,不新增第二套转圈、骨架或自动刷新。
|
||||
|
||||
|
||||
@@ -84,7 +84,6 @@ export function useBillingPanel(input: {
|
||||
readonly initialTab: BillingPaneTab;
|
||||
}) {
|
||||
const seedAccount = input.account;
|
||||
const [accountError, setAccountError] = useState("");
|
||||
const [paymentPackages, setPaymentPackages] = useState<MembershipProduct[]>([]);
|
||||
const [paymentEnabled, setPaymentEnabled] = useState(false);
|
||||
const [packagesError, setPackagesError] = useState("");
|
||||
@@ -160,7 +159,8 @@ export function useBillingPanel(input: {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
void fetchPackages();
|
||||
const timer = window.setTimeout(() => void fetchPackages(), 0);
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [fetchPackages]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -294,7 +294,6 @@ export function useBillingPanel(input: {
|
||||
|
||||
return {
|
||||
account: toBillingAccount(seedAccount),
|
||||
accountError,
|
||||
activeSubscription,
|
||||
createPayment,
|
||||
currentProductCode,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Home bootstrap failures are not one "the API is slow" bucket.
|
||||
*
|
||||
* `api-error` is the in-bundle account/session path (HTTP status or the 20s
|
||||
* cloud timeout). The other categories are what the inline dead-screen script
|
||||
* cloud slow-network timeout). The other categories are what the inline dead-screen script
|
||||
* can see before that bundle runs. Observation records only category, build
|
||||
* id, and duration — never a payload, exception string, or birth data.
|
||||
*/
|
||||
@@ -28,7 +28,7 @@ export type HomeBootstrapFailureInput = {
|
||||
resourceFromCache?: boolean;
|
||||
/** HTTP status from an account/session/model request the bundle actually made. */
|
||||
apiStatus?: number | null;
|
||||
/** Bundle-side cloud timeout (page.tsx 8000ms), not the dead-screen timer. */
|
||||
/** Bundle-side cloud slow-network timeout (page.tsx 20_000ms), not the dead-screen timer. */
|
||||
apiTimedOut?: boolean;
|
||||
};
|
||||
|
||||
|
||||
@@ -128,12 +128,11 @@ export function SessionListProvider({ children }: { children: ReactNode }) {
|
||||
const bootRef = useRef<SessionListBoot | null>(null);
|
||||
const controllerRef = useRef<AbortController | null>(null);
|
||||
const reloadRef = useRef<() => void>(() => undefined);
|
||||
const readyPackRef = useRef(createReadyGate());
|
||||
const [readyVersion, forceReadyVersion] = useState(0);
|
||||
const [readyPack, setReadyPack] = useState(createReadyGate);
|
||||
|
||||
useEffect(() => {
|
||||
let disposed = false;
|
||||
const load = (readyPack = readyPackRef.current) => {
|
||||
const load = (nextReadyPack: ReturnType<typeof createReadyGate>) => {
|
||||
controllerRef.current?.abort();
|
||||
const controller = new AbortController();
|
||||
controllerRef.current = controller;
|
||||
@@ -149,22 +148,21 @@ export function SessionListProvider({ children }: { children: ReactNode }) {
|
||||
setAccount(boot.account);
|
||||
setSignedOut(boot.signedOut);
|
||||
setSettled(true);
|
||||
readyPack.resolve();
|
||||
nextReadyPack.resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
if (disposed || controller.signal.aborted || controllerRef.current !== controller) return;
|
||||
bootRef.current = { sessions: [], rawRows: [], cursor: null, account: null, signedOut: false };
|
||||
setSettled(true);
|
||||
readyPack.resolve();
|
||||
nextReadyPack.resolve();
|
||||
});
|
||||
};
|
||||
reloadRef.current = () => {
|
||||
const nextReadyPack = createReadyGate();
|
||||
readyPackRef.current = nextReadyPack;
|
||||
forceReadyVersion((version) => version + 1);
|
||||
setReadyPack(nextReadyPack);
|
||||
load(nextReadyPack);
|
||||
};
|
||||
load();
|
||||
load(readyPack);
|
||||
return () => {
|
||||
disposed = true;
|
||||
reloadRef.current = () => undefined;
|
||||
@@ -180,7 +178,7 @@ export function SessionListProvider({ children }: { children: ReactNode }) {
|
||||
|
||||
const boot = useCallback(() => bootRef.current, []);
|
||||
|
||||
void readyVersion;
|
||||
const ready = readyPack.promise;
|
||||
const value = useMemo<SessionListContextValue>(() => ({
|
||||
sessions,
|
||||
setSessions,
|
||||
@@ -190,7 +188,7 @@ export function SessionListProvider({ children }: { children: ReactNode }) {
|
||||
setAccount,
|
||||
signedOut,
|
||||
settled,
|
||||
ready: readyPackRef.current.promise,
|
||||
ready,
|
||||
boot,
|
||||
reload,
|
||||
registerShellControls,
|
||||
@@ -203,7 +201,7 @@ export function SessionListProvider({ children }: { children: ReactNode }) {
|
||||
sessionsCursor,
|
||||
settled,
|
||||
signedOut,
|
||||
readyVersion,
|
||||
ready,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -7,7 +7,6 @@ import { EpayConfigurationError, resolveEpayConfig } from "../src/lib/epay/confi
|
||||
import { assertConfiguredEpayUrl, assertPublicEpayGateway, assertPublicGatewayUrl, isPublicEpayAddress } from "../src/lib/epay/gateway-policy";
|
||||
|
||||
const root = new URL("../", import.meta.url);
|
||||
const readProjectFile = (path: string) => readFileSync(new URL(path, root), "utf8");
|
||||
const route = readFileSync(new URL("src/app/api/admin/epay-settings/route.ts", root), "utf8");
|
||||
const management = readFileSync(new URL("src/components/admin/payment-management.tsx", root), "utf8");
|
||||
const createRoute = readFileSync(new URL("src/app/api/payment/epay/create/route.ts", root), "utf8");
|
||||
|
||||
@@ -15,7 +15,7 @@ test("packages load on mount without a redundant account request", () => {
|
||||
// 原值: 挂载并发 fetchAccountData() 与 fetchPackages(),并锁定 Promise.allSettled。
|
||||
// 新值: 挂载只执行 fetchPackages(),账户余额来自首页 bootstrap;成功兑换/支付使用接口返回 credits 通过共享事件同步。
|
||||
// 原因: BUG-1022 / TASK-home-slow-network D5,删除无用的完整 /api/account 请求,避免重复数据库读取。
|
||||
assert.match(hookSource, /void fetchPackages\(\);/);
|
||||
assert.match(hookSource, /setTimeout\(\(\) => void fetchPackages\(\), 0\)/);
|
||||
assert.doesNotMatch(hookSource, /Promise\.allSettled\(\[fetchAccountData\(\), fetchPackages\(\)\]\)/);
|
||||
assert.doesNotMatch(hookSource, /fetchAccountData/);
|
||||
assert.doesNotMatch(hookSource, /fetch\("\/api\/account"/);
|
||||
|
||||
Reference in New Issue
Block a user