- 同步 master 侧 248 个提交:会员与泥点计费(PR #588 / #603)、创作者主页与关注粉丝(PR #638)、运行页刷新真重载(PR #640)、AGC 模板 templateVersion 递增(PR #643)等;确认 master 未触碰发行网关与 `api-server/src/modules/game_distribution.rs`。 - 冲突 1(server-rs/crates/module-runtime/src/domain.rs:1157-1162)`RuntimeProfileWalletLedgerSourceType` 两侧各自在末尾追加变体:保留 master 的 `MembershipUpgradeGrant` 为索引 16(线上已落库口径),本分支 `GamePurchase` 顺延为索引 17,并保留其「每账号每游戏一次扣费」注释。 - 冲突 2(server-rs/crates/module-runtime/src/domain.rs:1184-1188)`as_str()` 同时保留 `membership_upgrade_grant` 与 `game_purchase` 两个分支。 - 冲突 3(server-rs/crates/spacetime-client/src/active/mapper/runtime_profile.rs:95-101)bindings→领域枚举映射同时保留 `MembershipUpgradeGrant` 与 `GamePurchase` 两支,按新索引顺序排列。 - 冲突 4(server-rs/crates/spacetime-client/src/module_bindings/runtime_profile_wallet_ledger_source_type_type.rs:43-47)生成枚举按模块源码顺序合并为 …`MembershipUpgradeGrant`、`GamePurchase`;随后 `npm run spacetime:generate` 复核该文件与生成结果逐字节一致。 - 冲突 5(server-rs/crates/api-server/src/admin.rs:4849-4853)sats 索引映射改为 `16 => membership_upgrade_grant` 与 `17 => game_purchase` 两条并存。 - 冲突 6(server-rs/crates/api-server/src/admin.rs:6368-6461)索引断言并入 master 的 `[16] => membership_upgrade_grant`,并把 master 的「17 尚未映射」占位断言替换为 `[17] => game_purchase`;本分支的后台消耗统计两个用例原样保留。 - 冲突 7(server-rs/crates/api-server/src/runtime_profile.rs:219-226)来源文案格式化同时保留 `MembershipUpgradeGrant` 与 `GamePurchase` 两支,注释随 `GamePurchase` 保留。 - 冲突 8(docs/project-memory/shared-memory/decision-log.md:3-24)两条决策记录并列保留:本分支 2026-10-05「播放会话前缀在三处入口清空 Cookie」在前,master 2026-10-03「每日免费发放额为 0 时前端隐藏该池」在后。 - 保住 master 侧:发行响应 ETag/304/gzip(`release_asset_response_with_cache` 五参形态与 `release_asset_etag` / `if_none_match_matches` / `accepts_gzip_encoding` / `gzip_release_asset` / `release_asset_not_modified_response`)、共享加载面 `PlatformGameLoadingSurface` 及其使用方、三池钱包与会员档位目录改造。 - 保住本分支侧:付费作品 404 守卫(`price_mud_points > 0` 且位于 `load_package` 之前)、购买与播放会话网关路由、nginx×3 / Pingora / Vite 的播放会话 Cookie 清空与 `nginx-route-parity.matrix.json` 登记、viewer 感知公开详情、后台审核价格、`PlatformGamePricingField` 共享定价组件与两端接入、AGC 项目版本只读 + 平台派发下一版本号、schema 与迁移白名单、钱包来源 `game_purchase`。 - 验证:`git merge-base --is-ancestor origin/master HEAD` 返回 0;`check:encoding`、`check:doc-index`、`check:spacetime-schema`、`check:server-rs-ddd`、`check:rustfmt`、`check:npm-workspaces`、`check:game-distribution-dto-parity`、`check:game-distribution-price-limit-parity`、`check:pingora-route-parity`、`check:nginx-spa-routes`、根/admin-web/AGC typecheck、`git diff --check` 全绿。 - 测试:`cargo test -p module-game-distribution` 30 passed,`cargo test -p api-server game_distribution` 61 passed,`cargo test -p spacetime-module game_distribution` 7 passed;定向 vitest 28 个文件 252 个用例全通过。 - `npm run spacetime:generate` 除 11 个 procedure 文件的纯空白格式差异外无任何语义改动(`git diff -w` 为空),已保留 master 的生成产物形态,提交内无 schema/绑定语义变化。
spacetime-client 共享 package 说明
日期:2026-05-01
1. package 职责
spacetime-client 是 SpacetimeDB 客户端适配 package,后续负责:
- 生成 bindings 后的客户端访问封装
- Axum 与各模块对 reducer、view、订阅的调用适配
- 身份透传、连接配置与基础错误处理适配
在 DDD 重构中,本 package 只承接 WP-SC Spacetime Client:
- 把 SpacetimeDB 生成绑定转换成
api-server可消费的 typed facade。 - 把 row snapshot / procedure result 转换成 BFF record。
- 统一 SDK 调用错误、业务 procedure 错误、缺失快照错误和超时错误。
- 不承载领域规则,不直接定义 table / reducer / procedure,不替代
spacetime-module。
当前约束见 ../../../docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md。
2. 当前完成口径
当前目录已不再只是占位。WP-SC Spacetime Client 在当前稳定 SpacetimeDB facade 范围内已经完成收尾:
- 通过
npm run spacetime:generate -- --rust-only生成并纳管公开 Rust bindings。 DbConnection调用连接池、单一缓存读连接、握手等待、超时和断线清理已封装在SpacetimeClient内部;调用池不订阅 read model,HTTP 角色额外使用一条共享连接保存订阅行缓存。- 已稳定的 assets、auth、AI task、Big Fish、Custom World、Puzzle、Runtime/Profile/Save、Story session、combat、inventory、NPC facade 均通过 typed 方法对外暴露。
- 生成绑定到 BFF record / module record 的 row snapshot mapper 已集中在
mapper.rs。 - SDK 调用错误、reducer 业务错误、procedure 业务错误、缺快照错误和本地输入校验错误已统一收口到
SpacetimeClientErrorhelper。 - Story runtime projection source 已复用 runtime inventory typed facade,读取投影不再只依赖 runtime snapshot 中的历史背包 JSON 副本。
- 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 时必须继续满足:
- 不手写
module_bindings生成物。 - 不在
spacetime-client内新增领域规则。 - procedure / reducer shape 稳定后再接 typed facade。
- 错误映射继续使用
SpacetimeClientErrorhelper。 - mapper 测试或 facade 定向测试随新增场景补齐。
2.1 module_bindings 生成物约束
src/module_bindings 目录下的 Rust 文件统一视为 SpacetimeDB CLI 生成产物,后续维护必须遵守:
- 只允许通过仓库根目录
npm run spacetime:generate -- --rust-only刷新,不允许手工修改。 - 不生成私有表绑定,不追加
--include-private;如后端需要读取私有表,应先在api-server或模块层补明确 contract,而不是让客户端 crate 直接依赖私有表结构。 - 不允许手工对该目录执行散装
rustfmt;若 SpacetimeDB CLI 已生成文件但自身 formatter 在 Windows 下失败,只能由scripts/generate-spacetime-bindings.mjs在短临时目录中分批rustfmt后同步。 src/lib.rs已通过#[rustfmt::skip] pub mod module_bindings;显式阻止 workspace 级cargo fmt继续递归格式化该目录。- Windows 下 SpacetimeDB CLI
2.1.0的生成后 formatter 可能因为一次性传入过多 Rust 文件路径而失败;仓库脚本会先输出到短临时目录,必要时接管分批格式化,再同步回本目录。
2.1.1 绑定缺文件恢复流程
若 mod.rs 已声明 *_table 模块,但目录内缺少对应 *_table.rs 文件,说明 Rust bindings 刷新不完整。不要手工补 generated code,统一在仓库根目录执行:
npm.cmd run spacetime:generate -- --rust-only
脚本内部会使用 --no-config:仓库根目录的 spacetime.json 同时配置了 TypeScript 与 Rust 两个生成目标,直接追加 --lang / --out-dir 会触发 SpacetimeDB CLI 的多目标参数冲突。
生成后用以下命令确认 mod.rs 声明的模块都有落盘文件:
$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 }
最后至少执行:
cargo check -p spacetime-client --manifest-path server-rs\Cargo.toml
3. 边界约束
spacetime-client只承接 SpacetimeDB 客户端访问适配,不承接具体业务模块的规则实现。- 业务状态真相仍由
apps/spacetime-module管理,业务编排由各模块 package 与apps/api-server承担。 - 不允许把 reducer、view、订阅调用细节重新散落到多个业务模块里各自实现。
- 新增 facade 必须等待对应
spacetime-modulefacade 稳定后再接,不提前假设 row shape。 src/module_bindings/**是生成产物,只能通过 SpacetimeDB CLI 生成流程刷新。