93 lines
5.7 KiB
Markdown
93 lines
5.7 KiB
Markdown
# spacetime-client 共享 package 说明
|
||
|
||
日期:`2026-05-01`
|
||
|
||
## 1. package 职责
|
||
|
||
`spacetime-client` 是 SpacetimeDB 客户端适配 package,后续负责:
|
||
|
||
1. 生成 bindings 后的客户端访问封装
|
||
2. Axum 与各模块对 reducer、view、订阅的调用适配
|
||
3. 身份透传、连接配置与基础错误处理适配
|
||
|
||
在 DDD 重构中,本 package 只承接 `WP-SC Spacetime Client`:
|
||
|
||
1. 把 SpacetimeDB 生成绑定转换成 `api-server` 可消费的 typed facade。
|
||
2. 把 row snapshot / procedure result 转换成 BFF record。
|
||
3. 统一 SDK 调用错误、业务 procedure 错误、缺失快照错误和超时错误。
|
||
4. 不承载领域规则,不直接定义 table / reducer / procedure,不替代 `spacetime-module`。
|
||
|
||
本轮方案见 [`SERVER_RS_DDD_WP_SC_SPACETIME_CLIENT_REFACTOR_2026-04-29.md`](../../../docs/technical/SERVER_RS_DDD_WP_SC_SPACETIME_CLIENT_REFACTOR_2026-04-29.md)。
|
||
|
||
## 2. 当前完成口径
|
||
|
||
当前目录已不再只是占位。`WP-SC Spacetime Client` 在当前稳定 SpacetimeDB facade 范围内已经完成收尾:
|
||
|
||
1. 通过 `npm run spacetime:generate -- --rust-only` 生成并纳管公开 Rust bindings。
|
||
2. `DbConnection` 连接池、握手等待、超时和断线清理已封装在 `SpacetimeClient` 内部。
|
||
3. 已稳定的 assets、auth、AI task、Big Fish、Custom World、Puzzle、Runtime/Profile/Save、Story session、combat、inventory、NPC facade 均通过 typed 方法对外暴露。
|
||
4. 生成绑定到 BFF record / module record 的 row snapshot mapper 已集中在 `mapper.rs`。
|
||
5. SDK 调用错误、reducer 业务错误、procedure 业务错误、缺快照错误和本地输入校验错误已统一收口到 `SpacetimeClientError` helper。
|
||
6. Story runtime projection source 已复用 runtime inventory typed facade,读取投影不再只依赖 runtime snapshot 中的历史背包 JSON 副本。
|
||
7. Story runtime 投影读取会对历史 `currentStory.options` 做兼容推断:若旧快照缺少 `scope`,仍会按 `functionId` 通过 `module-runtime-story` 的 option helper 还原为 `story / combat / npc` 作用域,避免旧存档把读取链路卡死。
|
||
|
||
`confirm_asset_object_and_return` 与 `bind_asset_object_to_entity_and_return` 的调用必须等到 SDK `on_connect` 回调后再发起。`DbConnection::build()` 只代表 WebSocket 已经初始化,不代表 SpacetimeDB 身份握手完成;如果过早调用 procedure,本地联调会表现为连接建立但请求长期没有回调,最终等到 idle timeout。
|
||
|
||
后续新增工作只随 `WP-ST` 新 table / reducer / procedure 或 row shape 稳定后按领域增量接入,不再把整个 `WP-SC` 包保持为进行中状态。新增 facade 时必须继续满足:
|
||
|
||
1. 不手写 `module_bindings` 生成物。
|
||
2. 不在 `spacetime-client` 内新增领域规则。
|
||
3. procedure / reducer shape 稳定后再接 typed facade。
|
||
4. 错误映射继续使用 `SpacetimeClientError` helper。
|
||
5. mapper 测试或 facade 定向测试随新增场景补齐。
|
||
|
||
## 2.1 `module_bindings` 生成物约束
|
||
|
||
`src/module_bindings` 目录下的 Rust 文件统一视为 SpacetimeDB CLI 生成产物,后续维护必须遵守:
|
||
|
||
1. 只允许通过仓库根目录 `npm run spacetime:generate -- --rust-only` 刷新,不允许手工修改。
|
||
2. 不生成私有表绑定,不追加 `--include-private`;如后端需要读取私有表,应先在 `api-server` 或模块层补明确 contract,而不是让客户端 crate 直接依赖私有表结构。
|
||
3. 不允许手工对该目录执行散装 `rustfmt`;若 SpacetimeDB CLI 已生成文件但自身 formatter 在 Windows 下失败,只能由 `scripts/generate-spacetime-bindings.mjs` 在短临时目录中分批 `rustfmt` 后同步。
|
||
4. `src/lib.rs` 已通过 `#[rustfmt::skip] pub mod module_bindings;` 显式阻止 workspace 级 `cargo fmt` 继续递归格式化该目录。
|
||
5. Windows 下 SpacetimeDB CLI `2.1.0` 的生成后 formatter 可能因为一次性传入过多 Rust 文件路径而失败;仓库脚本会先输出到短临时目录,必要时接管分批格式化,再同步回本目录。
|
||
|
||
### 2.1.1 绑定缺文件恢复流程
|
||
|
||
若 `mod.rs` 已声明 `*_table` 模块,但目录内缺少对应 `*_table.rs` 文件,说明 Rust bindings 刷新不完整。不要手工补 generated code,统一在仓库根目录执行:
|
||
|
||
```powershell
|
||
npm.cmd run spacetime:generate -- --rust-only
|
||
```
|
||
|
||
脚本内部会使用 `--no-config`:仓库根目录的 `spacetime.json` 同时配置了 TypeScript 与 Rust 两个生成目标,直接追加 `--lang` / `--out-dir` 会触发 SpacetimeDB CLI 的多目标参数冲突。
|
||
|
||
生成后用以下命令确认 `mod.rs` 声明的模块都有落盘文件:
|
||
|
||
```powershell
|
||
$modFile = 'server-rs\crates\spacetime-client\src\module_bindings\mod.rs'
|
||
$dir = 'server-rs\crates\spacetime-client\src\module_bindings'
|
||
$mods = Select-String -Path $modFile -Pattern '^pub mod ([a-zA-Z0-9_]+);' |
|
||
ForEach-Object { $_.Matches[0].Groups[1].Value }
|
||
$missing = @()
|
||
foreach ($m in $mods) {
|
||
if (-not (Test-Path (Join-Path $dir ($m + '.rs')))) {
|
||
$missing += $m
|
||
}
|
||
}
|
||
if ($missing.Count -eq 0) { 'missing module files: 0' } else { $missing }
|
||
```
|
||
|
||
最后至少执行:
|
||
|
||
```powershell
|
||
cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
|
||
```
|
||
|
||
## 3. 边界约束
|
||
|
||
1. `spacetime-client` 只承接 SpacetimeDB 客户端访问适配,不承接具体业务模块的规则实现。
|
||
2. 业务状态真相仍由 `apps/spacetime-module` 管理,业务编排由各模块 package 与 `apps/api-server` 承担。
|
||
3. 不允许把 reducer、view、订阅调用细节重新散落到多个业务模块里各自实现。
|
||
4. 新增 facade 必须等待对应 `spacetime-module` facade 稳定后再接,不提前假设 row shape。
|
||
5. `src/module_bindings/**` 是生成产物,只能通过 SpacetimeDB CLI 生成流程刷新。
|