Skip to content

[Web][交接] 端口层重构对前端的影响 —— 接着做应用区之前先看这一页 #107

Description

@yexiyue

6b0edbb1 + 03113937 已推到 develop,一次性落地六个 openspec change(端口层补齐 / 原子解除配对 / 设备名端口 / Web 取消与邀请预览 / 改名不重启节点)并跑了一轮 /simplify + 代码审查。动了不少前端契约,接着做 Web 应用区之前先看这一页,免得照着旧接口写。

关联:#98 #99 #100 #103 #104 已随这两个提交关闭。


一、破坏性契约变更(照旧写法会编不过或行为不对)

1. WebNode.inbox_items() 的返回类型变了

// 旧
inbox_items(includeArchived: boolean): Promise<InboxItemSummary[]>
// 新
inbox_items(includeArchived: boolean): Promise<InboxItemDetail[]>

返回的 detail 是完整的:files 已填、transfer 投影已在同一把锁下批量补好,语义与逐条 inbox_item() 一致(软删不返回、归档按开关、receivedAt 倒序)。

所以不要再写 1+N。旧代码是这样的,已经删掉了:

const summaries = await node.inbox_items(false);
const details = await Promise.all(summaries.map((i) => node.inbox_item(i.id)));
return details.filter((d): d is InboxItemDetail => d !== null);  // ← 这个 filter 是在补一个自制竞态

那个 filter 不是防御性编程,是在补「拉列表与拉详情之间条目可能已删」的窟窿——一次调用之后窟窿本身就不存在了。

inbox_item() / inbox_item_by_session() 没动,仍返回 InboxItemDetail | null
InboxItemSummary 已从 docs/app/app/_lib/view-types.ts 的 re-export 里删掉(应用区已零引用)。

2. 设备名:setDeviceName / rename_device 现在回传归一化结果

三端统一改成返回「真正落库的那个值」(string | null),不要再回读

// 旧:set 完再 get 一次,才知道后端把名字截成了什么
await commands.setDeviceName(name);
const stored = await commands.getDeviceName();
// 新
const stored = await commands.setDeviceName(name);

回读不只是多一次往返:两次调用之间另一个窗口或 MCP 改了名,回读拿到的是别人的值。桌面 src/lib/device-name.ts 与移动端都已改完,Web 的主路径(_lib/node-runtime.ts 节点在跑那条)本来就是对的。

⚠️ Web 还有一条 fallback 路径(节点没起来时走模块级 mod.set_device_name仍然需要回读,因为那个导出的签名是 Result<(), JsValue>、不回传结果。那条我刻意没改,注释里写了原因。

3. 改设备名不再重启节点

给 libp2p identify 加了运行时 agent_version setter(已提上游 libp2p/rust-libp2p#6576)。此前改一次名要断开所有连接、中断进行中的传输,现在既有连接原地更新、一个 RTT 内生效。

对前端的意义:改名可以做成一个普通的设置项,不需要任何「这会断开连接」的警示文案,也不需要在传输进行中禁用它。

4. 桌面传输历史查询不再依赖节点启动

get_transfer_projections / clear_transfer_history / get_transfer_source_paths 改成直接吃 store,不再经 NetManager。此前 /transfer 路由挂载即 loadProjections(),节点没 start 或 start 失败时整页报错。现在账本随时可查。

delete_transfer_session 仍走 manager——「进行中不可删」的域守卫在那里。

5. 三份自动生成的 bindings 都重生成了

src/lib/bindings.tscrates/web/bindings/bindings.tsmobile/packages/swarmdrop-core/src/generated/

它们此前都早已落后于已提交的 Rust,而且没有任何门禁拦这件事。所以这次的 diff 里有一批不属于本轮改动的存量修复:start 的参数个数、pauseTransfer 拆成 pauseSend/pauseReceive、新增 deviceRenamed / pairedDeviceRemoved 事件……前端能跑只是因为调用的恰好是交集。

规矩:改了跨 IPC/FFI 边界的类型就当场重生成并一起提交,别指望「下次 tauri dev 会自动更新」——那只在有人恰好跑 dev 时才发生,CI 从不跑 dev。命令与坑记在 dev-notes/knowledge/toolchain.md


二、新增的可复用件

docs/app/app/_components/confirm-action.tsx

两态确认(点一下 → 换成「警示文案 + 红色确认 + 返回」)。传输面板里三份手写的同款状态机已收进去。应用区新加破坏性操作用它,别再手写 useState(false)

两个出口,按 DOM 结构选:

用哪个 什么时候
<ConfirmAction /> 确认态就地顶掉触发按钮(列表项动作行)。绝大多数场景
useConfirmAction(){ trigger, panel } 触发按钮与确认区不在同一个位置(如按钮在面板头部、横幅在头部下方),两段节点交回调用方各自摆放

两条已经定死、别再各写各的语义:

  • 复位时机是「点确认的同一拍」,不等异步结果。 在途由调用方的 pending 表达(按钮文案变「清空中」),失败由调用方在自己的错误位渲染。改成「成功后复位」会让确认条在整个请求期间赖着不走。
  • error 不在组件里。 三处的错误卡位置各不相同(有的在横幅下方独立一行、有的与 projection.errorMessage 有固定先后),纳进组件就会挪动展示位置。

一个行为变化(我认为更对,但确实变了)

传输项的确认态此前是 item 级的,折叠期间会赖着——点了「取消」进确认态、折叠、再展开,看到的是上一次没点完的确认条。现在动作区只在展开时挂载,折叠即复位。确认是瞬时意图,离开视图就该作废。


三、几条容易踩的(不是新规矩,但这轮反复撞到)

  1. 改了 crates/web 必须 pnpm build:wasm 重烘,否则 docs/tsc 看到的是旧类型签名,会报出一堆假错误。这轮就有 agent 因此差点把正确的代码改回去。
  2. docs/app/app/_lib/create-store.ts 是自研 store,不是 zustand,同样有「selector 里派生新数组/对象 → 无限重渲染」的陷阱,而 pnpm check:zustand-access 只扫仓库根 src/,不覆盖 docs/。这块没有机器兜底,selector 一律只返回原始值或 store 内的稳定引用。
  3. 静态导出三限制没变:无 redirect()、运行时 ID 不进路由段(用 query param)、useSearchParams() 要套 <Suspense>;内部导航走 next/link(手写 <a href> 不加 basePath,GitHub Pages 子路径下全 404)。
  4. 收件箱是真表不是「已完成接收会话」的投影。 会话表有 HISTORY_CAP = 100 淘汰,收件箱条目不参与——「清空传输历史不动收件箱」这条不变量在浏览器上才成立。前端做「删除」时要分清删的是账本还是内容。

细节都在 dev-notes/knowledge/web-app-frontend.mdstorage-abstraction.md,这轮补了新的几节。


四、后续

前端相关的 follow-up 会另开 issue 指派过来,这一条只作背景,不用在它下面做事。有对不上的地方直接在这里问。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions