切断认证快照同步路径

删除 auth_store_snapshot 表和旧 JSON 快照 procedure。

改用 AuthStoreProjectionView 同步 user_account、auth_identity 和 refresh_session。

让 auth 服务从 user_account 投影恢复内存工作集。

同步生成绑定、schema guard 和后端架构文档。
This commit is contained in:
2026-07-01 19:07:21 +08:00
parent 69b4d5f090
commit 47083bfe05
38 changed files with 1123 additions and 1469 deletions
@@ -16,6 +16,14 @@
---
## 2026-07-01 认证工作集只经 typed projection 同步正式表
- 背景:同手机号重复账号、兑换码白名单错配和微信资料不回写暴露出 `module-auth` 内存工作集、`auth_store_snapshot` 和正式认证表之间仍有历史互刷路径;旧 JSON 快照会把过期手机号索引或用户资料重新带回运行态。
- 决策:删除 `auth_store_snapshot` 表和旧 `import_auth_store_snapshot_json` / `export_auth_store_snapshot_from_tables` procedure`module-auth` 只保留内存工作集和 typed `AuthStoreProjectionView` 导入 / 导出。运行中认证写操作通过 `sync_auth_store_projection` 同步 `user_account` / `auth_identity` / `refresh_session`,启动恢复通过 `export_auth_store_projection_from_tables` 从正式表恢复内存。账号资料真相只在 `user_account``auth_identity` 只保存登录入口身份键。
- 影响范围:`module-auth` projection API、`spacetime-module` auth schema/procedure、`spacetime-client` bindings/facade、`api-server` 启动恢复和认证同步、后端架构文档与认证排障记忆。
- 验证方式:`npm run spacetime:generate``SPACETIME_SCHEMA_GUARD_ALLOW_BREAKING=1 npm run check:spacetime-schema``cargo test -p module-auth --manifest-path server-rs/Cargo.toml -- --nocapture``cargo check -p spacetime-client --manifest-path server-rs/Cargo.toml``cargo check -p api-server --manifest-path server-rs/Cargo.toml``npm run check:encoding``git diff --check`
- 关联文档:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`
## 2026-06-29 图片画布手动抠图走远端 BiRefNet BFF
- 背景:用户手动“去除背景”面对任意图片,前端 `chromaKey` 和标准绿幕后处理不适合复杂人物、自然背景或非纯色背景;远端 image host 已部署 BiRefNet 服务,需要让手动抠图走高质量模型,同时避免把服务令牌暴露到浏览器。
+16 -16
View File
@@ -90,7 +90,7 @@
- 现象:后台把私有兑换码配给某个陶泥号或手机号后,用户用同一手机号登录兑换仍提示 `该兑换码不适用于当前账号`
- 原因:认证表里可能存在同一手机号的多条 `user_account`。如果认证工作集重建 `phone_to_user_id` 时让 `user_account.phone_number_e164` 后写覆盖前写,当前登录态会漂到没有 `auth_identity` 的重复账号,而兑换码白名单仍指向另一个内部 `user_id`
- 处理:重建认证工作集时以 `auth_identity(provider="phone")` 指向的账号作为手机号索引权威,`user_account.phone_number_e164` 只补没有 identity 的手机号;`auth_store_snapshot` 只允许在正式认证表为空时一次性转移到正式表,随后清空,不再作为运行期回灌来源;Bearer / refresh session 本进程未命中时不要再从 SpacetimeDB 导出整包快照刷新内存。线上止血先核对失败请求附近的 current session `user_id` 与兑换码 `allowed_user_ids`,不要只看手机号展示值。
- 处理:重建认证工作集时以 typed `AuthStoreProjectionView``user_account` / `auth_identity` / `refresh_session` 恢复;手机号索引以 `auth_identity(provider="phone")` 指向的账号权威,`user_account.phone_number_e164` 只补没有 identity 的手机号;`auth_store_snapshot` 表和旧 JSON procedure 已删除,Bearer / refresh session 本进程未命中时不要再从 SpacetimeDB 导出整包状态刷新内存。线上止血先核对失败请求附近的 current session `user_id` 与兑换码 `allowed_user_ids`,不要只看手机号展示值。
- 约束:`auth_identity` 只保存登录入口身份键;手机号、昵称和头像的正式资料真相在 `user_account.phone_number_e164` / `display_name` / `avatar_url`。旧 `auth_identity.phone_e164` / `display_name` / `avatar_url` 只能作为历史回填来源,不能继续让新写入依赖这些列。
- 验证:`cargo test -p spacetime-module auth_export -- --nocapture` 应覆盖同手机号重复账号时手机号索引优先指向有 phone identity 的账号;`api-server` 中不应再存在运行期 `refresh_auth_store_from_spacetime` 调用。
- 关联:`server-rs/crates/spacetime-module/src/auth/procedures.rs``server-rs/crates/spacetime-module/src/auth/tables.rs``server-rs/crates/module-auth/src/lib.rs`
@@ -400,12 +400,12 @@
- 验证:`systemctl status genarrative-external-generation-controller.service 'genarrative-external-generation-worker@*.service'` 能看到 controller 和 worker 实例;queue 模式下任务被 claim 后 `worker_id``lease_expires_at` 会更新,完成后 session 进入 ready 或 failedinline 模式下不应产生新的 `external_generation_job`
- 关联:`deploy/systemd/genarrative-external-generation-worker@.service``deploy/systemd/genarrative-external-generation-controller.service``deploy/env/external-generation-controller.env.example``server-rs/crates/spacetime-module/src/external_generation.rs``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 外部生成 worker 不应等待 HTTP 认证快照恢复
## 外部生成 worker 不应等待 HTTP 认证投影恢复
- 现象:`genarrative-external-generation-worker@1.service` 在 systemd 中显示 active,但 `external_generation_job` 长时间保持 `pending`worker 日志每 5 秒出现 `export_auth_store_snapshot_from_tables` 订阅失败,例如缺少 `public_work_gallery_entry` 公开 read model
- 原因:独立 worker / controller 是非 HTTP 角色,不承接用户登录态恢复;如果启动路径复用 HTTP `api-server` 的认证快照恢复,SpacetimeDB 认证投影或公开 read model 漂移会把 worker claim 循环挡在启动前。
- 处理:`GENARRATIVE_PROCESS_ROLE=external-generation-worker``external-generation-controller` 启动时只构建空 auth store 的 `AppState`,不调用 SpacetimeDB 认证快照导出;只有 `api` / `all` 这类 HTTP 角色需要在启动时恢复认证快照并在依赖不可用时重试或进入 503 降级。
- 验证:重启 worker 后日志应先出现“非 HTTP 进程跳过 SpacetimeDB 认证快照恢复”,随后出现 `external generation worker 已启动`;同一时间窗口不应再因为 `export_auth_store_snapshot_from_tables` 缺表而阻止 job claim。HTTP `api-server` 的认证恢复日志和 503 降级语义保持不变。
- 现象:`genarrative-external-generation-worker@1.service` 在 systemd 中显示 active,但 `external_generation_job` 长时间保持 `pending`worker 日志每 5 秒出现认证投影或公开 read model 订阅失败
- 原因:独立 worker / controller 是非 HTTP 角色,不承接用户登录态恢复;如果启动路径复用 HTTP `api-server` 的认证投影恢复,SpacetimeDB 认证投影或公开 read model 漂移会把 worker claim 循环挡在启动前。
- 处理:`GENARRATIVE_PROCESS_ROLE=external-generation-worker``external-generation-controller` 启动时只构建空 auth store 的 `AppState`,不调用 SpacetimeDB 认证投影导出;只有 `api` / `all` 这类 HTTP 角色需要在启动时恢复认证投影并在依赖不可用时重试或进入 503 降级。
- 验证:重启 worker 后日志应先出现“非 HTTP 进程跳过 SpacetimeDB 认证投影恢复”,随后出现 `external generation worker 已启动`;同一时间窗口不应再因为认证投影恢复失败而阻止 job claim。HTTP `api-server` 的认证恢复日志和 503 降级语义保持不变。
- 关联:`server-rs/crates/api-server/src/main.rs``server-rs/crates/api-server/src/external_generation_worker.rs``server-rs/crates/api-server/src/external_generation_worker_controller.rs``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 本地旧 external-generation-worker 会抢队列并暴露成 procedure 超时
@@ -1197,27 +1197,27 @@
- 验证:生成文件落在 `public/branding/taonier-logo-*/`,用 Pillow 检查图片尺寸和非空;执行 `node --check scripts/generate-taonier-logo-concepts.mjs``npm run check:encoding``git diff --check`
- 关联:`scripts/generate-taonier-logo-concepts.mjs``docs/design/TAONIER_BRAND_LOGO_CONCEPTS_2026-05-13.md`
## 忘记密码后仍提示手机号或密码错误先查认证快照同步
## 忘记密码后仍提示手机号或密码错误先查认证投影同步
- 现象:用户通过“忘记密码”重设密码后,接口返回成功或页面进入登录态,但再次使用新密码登录仍提示“手机号或密码错误”;重启后还可能出现 `Bearer JWT 版本已失效`,日志里的 token version 与本地快照不一致。
- 原因:重置/修改密码会更新 `password_hash``password_login_enabled``token_version`,如果 API 层只更新本地 `InMemoryAuthStore`,没有调用 `sync_auth_store_tables_to_spacetime()``api-server` 重启时可能从旧的 SpacetimeDB 正式认证表恢复账号状态。
- 处理:`POST /api/auth/password/change``POST /api/auth/password/reset` 成功后必须同步正式认证表。2026-06-30 起,`auth_store_snapshot` 不再保留行级备查,也不作为运行期回灌来源;只在正式认证表为空时把最新旧快照转移一次到 `user_account` / `auth_identity` / `refresh_session` 并立即清空旧表。认证创建、登录会话、刷新、退出、改密、重置密码、绑定和资料变更等写操作必须在返回客户端前成功同步 SpacetimeDB;同步失败时接口返回错误,不允许把只存在于当前进程内存的账号或会话当成成功结果。新用户注册奖励、邀请码绑定和登录埋点必须排在认证同步成功之后,避免认证没落库时先写出钱包或邀请关系。
- 处理:`POST /api/auth/password/change``POST /api/auth/password/reset` 成功后必须同步正式认证表。2026-07-01 起,`auth_store_snapshot` 表和旧 JSON procedure 已删除;认证工作集只通过 typed projection 同步 `user_account` / `auth_identity` / `refresh_session`。认证创建、登录会话、刷新、退出、改密、重置密码、绑定和资料变更等写操作必须在返回客户端前成功同步 SpacetimeDB;同步失败时接口返回错误,不允许把只存在于当前进程内存的账号或会话当成成功结果。新用户注册奖励、邀请码绑定和登录埋点必须排在认证同步成功之后,避免认证没落库时先写出钱包或邀请关系。
- 验证:执行 `cargo test -p module-auth password --manifest-path server-rs/Cargo.toml``cargo test -p api-server password --manifest-path server-rs/Cargo.toml`;手测时重设密码后旧密码应失败,新密码应成功,重启后仍应保持。
- 关联:`server-rs/crates/api-server/src/password_management.rs``server-rs/crates/api-server/src/state.rs``docs/technical/PASSWORD_LOGIN_CHANGE_RESET_DESIGN_2026-04-24.md`
## 密码登录失败且短信登录提示手机号已存在先查孤儿手机号索引
- 现象:老账号用密码登录提示“手机号或密码错误”,改用短信验证码登录又提示“手机号已存在 / 已注册”,用户卡在既不能登录也不能重新创建的状态。
- 原因:历史版本或停服务时认证同步不完整,可能在 SpacetimeDB `auth_identity(provider=phone)``module-auth` 快照里留下 `phone_to_user_id` 映射,但对应 `user_account` / `users_by_username` 用户行已经不存在。密码登录按手机号索引找不到真实用户,短信登录尝试创建新用户时又被孤儿手机号索引挡住。
- 处理:`export_auth_store_snapshot_from_tables` 导出时必须过滤没有 `user_account` phone / wechat identity、union 索引和 refresh session`module-auth` 从 JSON 快照恢复时也必须二次丢弃指向不存在用户的索引。运行时创建手机号用户前若发现手机号映射指向不存在的用户,应删除孤儿映射后继续创建,避免死锁态继续扩散。
- 验证:`cargo test -p module-auth snapshot_json_drops_orphan_phone_index_before_phone_login --manifest-path server-rs/Cargo.toml``cargo test -p module-auth phone --manifest-path server-rs/Cargo.toml``cargo test -p spacetime-module auth --manifest-path server-rs/Cargo.toml``cargo test -p api-server phone_login_reuses_existing_user_for_same_phone_number --manifest-path server-rs/Cargo.toml`
- 原因:历史版本或停服务时认证同步不完整,可能在 SpacetimeDB `auth_identity(provider=phone)` `module-auth` 快照里留下 `phone_to_user_id` 映射,但对应 `user_account` / `users_by_username` 用户行已经不存在。密码登录按手机号索引找不到真实用户,短信登录尝试创建新用户时又被孤儿手机号索引挡住。
- 处理:`export_auth_store_projection_from_tables` 导出正式认证表 projection`module-auth` 从 projection 恢复时必须丢弃指向不存在 `user_account` 的 identity、union 索引和 refresh session。运行时创建手机号用户前若发现手机号映射指向不存在的用户,应删除孤儿映射后继续创建,避免死锁态继续扩散。
- 验证:`cargo test -p module-auth projection --manifest-path server-rs/Cargo.toml``cargo test -p module-auth phone --manifest-path server-rs/Cargo.toml``cargo test -p api-server phone_login_reuses_existing_user_for_same_phone_number --manifest-path server-rs/Cargo.toml`
- 关联:`server-rs/crates/module-auth/src/lib.rs``server-rs/crates/spacetime-module/src/auth/procedures.rs``docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`
## 认证本地文件快照已废弃,旧 procedure 已删
## 认证快照表和旧 procedure 已删
- 现象:有些旧代码和生成 bindings 里还会残留 `get_auth_store_snapshot``upsert_auth_store_snapshot``import_auth_store_snapshot`,或者把 `auth-store.json` 误当成认证恢复源。
- 原因:认证恢复已经彻底收口到 SpacetimeDB 正式表和 `module-auth` 的 JSON 导入 / 导出路径;本地文件持久化会和正式表投影打架,SpacetimeDB 不可用时还可能把旧快照回灌到用户表。
- 处理:先用 `npm run spacetime:generate -- --rust-only` 刷新 bindings,确认 `server-rs/crates/spacetime-client/src/module_bindings.rs` 里已没有旧 procedure 导出;`module-auth` 只保留内存态,不再写本地快照文件。
- 现象:有些旧代码和生成 bindings 里还会残留 `get_auth_store_snapshot``upsert_auth_store_snapshot``import_auth_store_snapshot``import_auth_store_snapshot_json``export_auth_store_snapshot_from_tables`,或者把 `auth-store.json` 误当成认证恢复源。
- 原因:认证恢复已经彻底收口到 SpacetimeDB 正式表和 `module-auth` typed projection;本地文件持久化或 JSON 快照会和正式表投影打架,SpacetimeDB 不可用时还可能把旧快照回灌到用户表。
- 处理:先用 `npm run spacetime:generate` 刷新 bindings,确认 `server-rs/crates/spacetime-client/src/module_bindings.rs` 里已没有旧 snapshot table / procedure 导出;`module-auth` 只保留内存态和 projection view,不再写本地快照文件。
- 验证:`cargo check -p module-auth --manifest-path server-rs/Cargo.toml``cargo check -p api-server --manifest-path server-rs/Cargo.toml``npm run check:spacetime-schema``npm run check:encoding`
## 抓大鹅生成页只显示服务暂不可用先查 reason 和外部服务配置
@@ -2387,7 +2387,7 @@
## 本地 api-server 启动订阅 401 先查 Web identity token 注入
- 现象:`npm run dev` 启动到 api-server 恢复认证快照时,日志出现 `Failed to initiate WebSocket connection ... /v1/database/<db>/subscribe?compression=Brotli: HTTP error: 401 Unauthorized`
- 现象:`npm run dev` 启动到 api-server 恢复认证投影时,日志出现 `Failed to initiate WebSocket connection ... /v1/database/<db>/subscribe?compression=Brotli: HTTP error: 401 Unauthorized`
- 原因:SpacetimeDB SDK 订阅需要 Web API identity token;本地 `.env.local` 常把 `GENARRATIVE_SPACETIME_TOKEN` 留空,只靠 CLI 登录态 publish 成功并不能让 api-server 的 WebSocket subscribe 获得权限。
- 处理:`scripts/dev.mjs` 在 SpacetimeDB 就绪后调用 `/v1/identity` 创建当前进程专用 Web API identity token,并只注入本次 `api-server` 环境;不要把临时 token 写进 `.env.local` 或日志。若仍报 401,先确认是否使用了项目脚本启动、日志是否出现 `已创建本地 Web identity`,以及 `GENARRATIVE_SPACETIME_SERVER_URL` / 数据库名是否指向本次启动的实例。
- 验证:`npm run test -- scripts/dev.test.ts`;重新运行 `npm run dev` 后 api-server 启动日志不再出现上述 subscribe 401`/healthz` 返回 200。
@@ -1,6 +1,6 @@
# server-rs 与 SpacetimeDB 数据契约
更新时间:`2026-06-24`
更新时间:`2026-07-01`
## 后端主线
@@ -290,16 +290,9 @@ npm run check:server-rs-ddd
- Rust 结构体:`AuthStoreProjectionMeta`
- 源码:`server-rs/crates/spacetime-module/src/auth/tables.rs`
### `auth_store_snapshot`
认证恢复策略:`api-server` 启动时只从 SpacetimeDB 正式认证表(`user_account` / `auth_identity` / `refresh_session`)导出 typed `AuthStoreProjectionView`,再恢复 `module-auth` 的进程内认证工作集;运行中 Bearer `sid` 或 refresh cookie 在本进程工作集内未命中时直接按失效处理,不再从 SpacetimeDB 导出整包认证状态刷新内存,避免旧投影把重复手机号或旧会话重新灌回进程。`module-auth` 只保留内存工作集和 projection 导入 / 导出能力,不再保留 JSON 快照导入 / 导出能力,也不写本地持久化文件;`auth-store.json` / `GENARRATIVE_AUTH_STORE_PATH` 不再是兼容恢复源。认证创建、登录会话、刷新、退出、改密、重置密码、绑定和资料变更等写操作必须在返回客户端前通过 `sync_auth_store_projection` 成功同步 SpacetimeDB 正式认证表;同步失败时接口返回错误,不允许把只存在于当前进程内存的账号或会话当成成功结果。新用户注册奖励、邀请码绑定和登录埋点必须排在认证同步成功之后,避免认证没落库时先写出钱包或邀请关系。若启动恢复阶段 SpacetimeDB 不可连接或超时,`api-server` 会按固定间隔持续重试认证工作集恢复,恢复成功后才开始监听 HTTP,避免一次短超时让进程永久停留在依赖不可用状态。
- Rust 结构体:`AuthStoreSnapshot`
- 源码:`server-rs/crates/spacetime-module/src/auth/tables.rs`
认证恢复策略:`api-server` 启动时只从 SpacetimeDB 正式认证表(`user_account` / `auth_identity` / `refresh_session`)投影恢复进程内认证工作集;运行中 Bearer `sid` 或 refresh cookie 在本进程工作集内未命中时直接按失效处理,不再从 SpacetimeDB 导出整包认证状态刷新内存,避免旧投影把重复手机号或旧会话重新灌回进程。`module-auth` 只保留内存工作集和 JSON 导入 / 导出能力,不再写本地持久化文件;`auth-store.json` / `GENARRATIVE_AUTH_STORE_PATH` 不再是兼容恢复源,也不得在启动时回写覆盖 `auth_identity` / `user_account`。认证创建、登录会话、刷新、退出、改密、重置密码、绑定和资料变更等写操作必须在返回客户端前成功同步 SpacetimeDB 正式认证表;同步失败时接口返回错误,不允许把只存在于当前进程内存的账号或会话当成成功结果。新用户注册奖励、邀请码绑定和登录埋点必须排在认证同步成功之后,避免认证没落库时先写出钱包或邀请关系。若启动恢复阶段 SpacetimeDB 不可连接或超时,`api-server` 会按固定间隔持续重试认证工作集恢复,恢复成功后才开始监听 HTTP,避免一次短超时让进程永久停留在依赖不可用状态。
`auth_store_snapshot` 禁止再写单行 `snapshot_id = "default"` 聚合 JSON,也不再保留行级备查。SpacetimeDB 模块只保留 `import_auth_store_snapshot_json``export_auth_store_snapshot_from_tables` 两个兼容过程:前者把当前 `module-auth` 工作集导入正式认证表并清空旧快照表;后者只在正式认证表为空时把最新旧快照转移一次到正式认证表,然后清空 `auth_store_snapshot`。旧 `get_auth_store_snapshot``upsert_auth_store_snapshot``import_auth_store_snapshot` 兼容入口已删除。导入正式表时只按主键 upsert 本次快照包含的用户、身份和会话,避免过期快照把其他用户整表删除。
导出认证快照时,`auth_identity``refresh_session` 只能引用仍存在于 `user_account` 的用户;孤儿手机号 identity、微信 identity、union 索引或 refresh session 必须被过滤,不能恢复成 `module-auth` 内存态里的 `phone_to_user_id` 死索引。`module-auth` 从 JSON 快照恢复时也要二次清理这些孤儿索引,避免历史坏快照导致密码登录提示错误、短信登录又提示手机号已存在。
`auth_store_snapshot` 表和旧 `import_auth_store_snapshot_json` / `export_auth_store_snapshot_from_tables` procedure 已删除。认证投影同步只读写 `user_account``auth_identity``refresh_session``auth_store_projection_meta``auth_identity` 不再写 `phone_e164``display_name``avatar_url`,这些账号资料只以 `user_account` 为准。
### `bark_battle_draft_config`
@@ -930,6 +923,7 @@ RPG 创作入口的配置 ID 是 `rpg`,当前 `visible=true`、`open=true`
- Rust 结构体:`UserAccount`
- 源码:`server-rs/crates/spacetime-module/src/auth/tables.rs`
- 职责:账号资料真相源,保存 `phone_number_e164``display_name``avatar_url``created_at`、登录状态、密码 hash、token version 和账号标签。`module-auth` 进程内工作集必须通过 typed projection 与该表同步,不得再经 auth JSON 快照回灌。
### `user_browse_history`
+3 -1
View File
@@ -621,10 +621,12 @@ function main() {
const compareResult = compareTables(baseResult.tables, currentResult.tables);
const changedFiles = getChangedFiles(baseRef);
const sidecarFailures = checkSchemaSidecars(changedFiles, compareResult.schemaChanged);
const compareFailures =
compareResult.breakingChanged && allowBreaking ? [] : compareResult.failures;
const failures = [
...currentResult.failures,
...baseResult.failures,
...compareResult.failures,
...compareFailures,
...sidecarFailures,
];
+1
View File
@@ -5770,6 +5770,7 @@ version = "0.1.0"
dependencies = [
"module-ai",
"module-assets",
"module-auth",
"module-big-fish",
"module-combat",
"module-custom-world",
+9 -1
View File
@@ -521,7 +521,7 @@ mod tests {
#[tokio::test]
async fn spacetime_unavailable_router_returns_service_unavailable_for_requests() {
let app =
build_spacetime_unavailable_router("SpacetimeDB 启动恢复认证快照超时".to_string());
build_spacetime_unavailable_router("SpacetimeDB 启动恢复认证投影超时".to_string());
let response = app
.oneshot(
@@ -2806,6 +2806,10 @@ mod tests {
login_payload["user"]["wechatDisplayName"],
Value::String("微信旅人".to_string())
);
assert_eq!(
login_payload["user"]["displayName"],
Value::String("微信旅人".to_string())
);
assert_eq!(
login_payload["user"]["wechatAccount"],
Value::String("wx-mini-code-001".to_string())
@@ -2969,6 +2973,10 @@ mod tests {
bind_payload["user"]["wechatDisplayName"],
Value::String("微信旅人".to_string())
);
assert_eq!(
bind_payload["user"]["displayName"],
Value::String("微信旅人".to_string())
);
assert!(
bind_payload["token"]
.as_str()
+4 -4
View File
@@ -219,7 +219,7 @@ fn build_non_http_app_state_for_startup(
debug_assert!(!should_restore_auth_store_for_startup(process_role));
info!(
process_role = process_role.as_str(),
"非 HTTP 进程跳过 SpacetimeDB 认证快照恢复"
"非 HTTP 进程跳过 SpacetimeDB 认证投影恢复"
);
AppState::new_with_empty_auth_store(config)
}
@@ -436,7 +436,7 @@ async fn restore_app_state_for_startup(
warn!(
retry_after_seconds = AUTH_STORE_STARTUP_RETRY_INTERVAL.as_secs(),
error = %message,
"启动恢复 SpacetimeDB 认证快照暂不可用,api-server 将继续重试"
"启动恢复 SpacetimeDB 认证投影暂不可用,api-server 将继续重试"
);
tokio::time::sleep(AUTH_STORE_STARTUP_RETRY_INTERVAL).await;
}
@@ -458,10 +458,10 @@ async fn try_restore_app_state_for_startup(
Err(_) => {
error!(
timeout_seconds = AUTH_STORE_STARTUP_RESTORE_TIMEOUT.as_secs(),
"启动等待 SpacetimeDB 恢复认证快照超时"
"启动等待 SpacetimeDB 恢复认证投影超时"
);
Err(state::AppStateInitError::DependencyUnavailable(
"SpacetimeDB 启动恢复认证快照超时".to_string(),
"SpacetimeDB 启动恢复认证投影超时".to_string(),
))
}
}
+25 -25
View File
@@ -782,27 +782,26 @@ impl AppState {
#[cfg(test)]
return Ok(());
#[cfg(not(test))]
let snapshot_json = self
.auth_store
.export_snapshot_json()
.map_err(SpacetimeClientError::Runtime)?;
#[cfg(not(test))]
let updated_at_micros = i64::try_from(
OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000,
)
.map_err(|_| SpacetimeClientError::Runtime("认证状态更新时间超出 i64 范围".to_string()))?;
// 当前仍由 module-auth 的进程内工作集执行业务规则;这里只同步到 SpacetimeDB 正式认证表,
// 不再读写 auth_store_snapshot 行镜像。
#[cfg(not(test))]
let projection = self
.auth_store
.export_projection_view(updated_at_micros)
.map_err(SpacetimeClientError::Runtime)?;
// 当前仍由 module-auth 的进程内工作集执行业务规则;这里只用 typed projection 同步正式认证表。
#[cfg(not(test))]
if let Err(error) = self
.spacetime_client
.import_auth_store_snapshot_json(snapshot_json, updated_at_micros)
.sync_auth_store_projection(projection)
.await
{
warn!(
error = %error,
"认证状态导入 SpacetimeDB 正式表失败,当前认证流程中止"
"认证投影同步 SpacetimeDB 正式表失败,当前认证流程中止"
);
return Err(error);
}
@@ -824,33 +823,33 @@ impl AppState {
let mut restore_errors = Vec::new();
match spacetime_client
.export_auth_store_snapshot_from_tables()
.export_auth_store_projection_from_tables()
.await
{
Ok(snapshot) => {
Ok(projection) => {
spacetime_restore_available = true;
if let Some(candidate) = auth_store_candidate_from_snapshot_record(
snapshot,
if let Some(candidate) = auth_store_candidate_from_projection_view(
projection,
AuthStoreRestoreSource::SpacetimeTables,
)? {
let state = Self::new_with_auth_store(config, candidate.auth_store)?;
info!(
source = candidate.source.as_str(),
updated_at_micros = candidate.updated_at_micros,
"已恢复认证快照"
"已恢复认证投影"
);
return Ok(state);
}
}
Err(error) => {
warn!(error = %error, "从 SpacetimeDB 表恢复认证快照失败");
warn!(error = %error, "从 SpacetimeDB 表恢复认证投影失败");
restore_errors.push(error.to_string());
}
}
if !spacetime_restore_available {
return Err(AppStateInitError::DependencyUnavailable(format!(
"SpacetimeDB 认证恢复不可用:{}",
"SpacetimeDB 认证投影恢复不可用:{}",
restore_errors.join("; ")
)));
}
@@ -1244,22 +1243,23 @@ struct AuthStoreRestoreCandidate {
auth_store: InMemoryAuthStore,
}
fn auth_store_candidate_from_snapshot_record(
snapshot: spacetime_client::AuthStoreSnapshotRecord,
fn auth_store_candidate_from_projection_view(
projection: module_auth::AuthStoreProjectionView,
source: AuthStoreRestoreSource,
) -> Result<Option<AuthStoreRestoreCandidate>, AppStateInitError> {
let Some(snapshot_json) = snapshot
.snapshot_json
.filter(|value| !value.trim().is_empty())
else {
if projection.users.is_empty()
&& projection.identities.is_empty()
&& projection.refresh_sessions.is_empty()
{
return Ok(None);
};
let auth_store = InMemoryAuthStore::from_snapshot_json(&snapshot_json)
}
let updated_at_micros = Some(projection.updated_at_micros);
let auth_store = InMemoryAuthStore::from_projection_view(projection)
.map_err(AppStateInitError::AuthStore)?;
Ok(Some(AuthStoreRestoreCandidate {
source,
updated_at_micros: snapshot.updated_at_micros,
updated_at_micros,
auth_store,
}))
}
@@ -2,11 +2,7 @@
//!
//! 这里只返回纯应用结果与领域事件;短信 provider、JWT 签发和持久化由外层 adapter 完成。
use serde::{Deserialize, Serialize};
use crate::domain::{
AuthStoreSnapshotRecord, AuthUser, RefreshSessionRecord, WechatAuthStateRecord,
};
use crate::domain::{AuthUser, RefreshSessionRecord, WechatAuthStateRecord};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AuthMeResult {
@@ -111,20 +107,7 @@ pub struct LogoutCurrentSessionResult {
pub user: AuthUser,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RefreshAuthStoreSnapshotResult {
pub user_count: usize,
pub session_count: usize,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LogoutAllSessionsResult {
pub user: AuthUser,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuthStoreSnapshotProcedureResult {
pub ok: bool,
pub record: Option<AuthStoreSnapshotRecord>,
pub error_message: Option<String>,
}
@@ -2,8 +2,6 @@
//!
//! 用于表达密码入口、手机号验证码、微信登录、刷新会话签发和吊销等用例输入。
use serde::{Deserialize, Serialize};
use crate::domain::{
AuthLoginMethod, PhoneAuthScene, RefreshSessionClientInfo, WechatAuthScene,
WechatIdentityProfile,
@@ -106,9 +104,3 @@ pub struct LogoutCurrentSessionInput {
pub struct LogoutAllSessionsInput {
pub user_id: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuthStoreSnapshotUpsertInput {
pub snapshot_json: String,
pub updated_at_micros: i64,
}
+47 -4
View File
@@ -178,11 +178,54 @@ pub struct RefreshSessionRecord {
pub last_seen_at: String,
}
/// Auth store 持久化快照记录
/// module-auth 进程内工作集同步到数据库的 typed view
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuthStoreSnapshotRecord {
pub snapshot_json: Option<String>,
pub updated_at_micros: Option<i64>,
pub struct AuthStoreProjectionView {
pub updated_at_micros: i64,
pub users: Vec<AuthStoreProjectionUser>,
pub identities: Vec<AuthStoreProjectionIdentity>,
pub refresh_sessions: Vec<AuthStoreProjectionRefreshSession>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuthStoreProjectionUser {
pub user_id: String,
pub public_user_code: String,
pub username: String,
pub display_name: String,
pub avatar_url: Option<String>,
pub phone_number_masked: Option<String>,
pub phone_number_e164: Option<String>,
pub login_method: String,
pub binding_status: String,
pub wechat_bound: bool,
pub password_hash: String,
pub password_login_enabled: bool,
pub token_version: u64,
pub created_at: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuthStoreProjectionIdentity {
pub identity_id: String,
pub user_id: String,
pub provider: String,
pub provider_uid: String,
pub provider_union_id: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuthStoreProjectionRefreshSession {
pub session_id: String,
pub user_id: String,
pub refresh_token_hash: String,
pub issued_by_provider: String,
pub client_info_json: String,
pub expires_at: String,
pub revoked_at: Option<String>,
pub created_at: String,
pub updated_at: String,
pub last_seen_at: String,
}
pub fn validate_password(password: &str) -> Result<(), PasswordEntryError> {
File diff suppressed because it is too large Load Diff
@@ -7,6 +7,7 @@ license.workspace = true
[dependencies]
module-ai = { workspace = true }
module-assets = { workspace = true }
module-auth = { workspace = true }
module-big-fish = { workspace = true }
module-combat = { workspace = true }
module-custom-world = { workspace = true }
+20 -26
View File
@@ -1,18 +1,18 @@
use super::*;
impl SpacetimeClient {
pub async fn export_auth_store_snapshot_from_tables(
pub async fn export_auth_store_projection_from_tables(
&self,
) -> Result<AuthStoreSnapshotRecord, SpacetimeClientError> {
) -> Result<module_auth::AuthStoreProjectionView, SpacetimeClientError> {
self.call_after_connect(
"export_auth_store_snapshot_from_tables",
"export_auth_store_projection_from_tables",
move |connection, sender| {
connection
.procedures()
.export_auth_store_snapshot_from_tables_then(move |_, result| {
.export_auth_store_projection_from_tables_then(move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_auth_store_snapshot_procedure_result);
.and_then(map_auth_store_projection_procedure_result);
send_once(&sender, mapped);
});
},
@@ -20,29 +20,23 @@ impl SpacetimeClient {
.await
}
pub async fn import_auth_store_snapshot_json(
pub async fn sync_auth_store_projection(
&self,
snapshot_json: String,
updated_at_micros: i64,
) -> Result<AuthStoreSnapshotImportRecord, SpacetimeClientError> {
let procedure_input = AuthStoreSnapshotUpsertInput {
snapshot_json,
updated_at_micros,
};
view: module_auth::AuthStoreProjectionView,
) -> Result<AuthStoreProjectionSyncRecord, SpacetimeClientError> {
let procedure_input = map_auth_store_projection_view_input(view);
self.call_after_connect(
"import_auth_store_snapshot_json",
move |connection, sender| {
connection
.procedures()
.import_auth_store_snapshot_json_then(procedure_input, move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_auth_store_snapshot_import_procedure_result);
send_once(&sender, mapped);
});
},
)
self.call_after_connect("sync_auth_store_projection", move |connection, sender| {
connection.procedures().sync_auth_store_projection_then(
procedure_input,
move |_, result| {
let mapped = result
.map_err(SpacetimeClientError::from_sdk_error)
.and_then(map_auth_store_projection_sync_procedure_result);
send_once(&sender, mapped);
},
);
})
.await
}
}
+1 -7
View File
@@ -333,13 +333,7 @@ impl SpacetimeClientHealthSnapshot {
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AuthStoreSnapshotRecord {
pub snapshot_json: Option<String>,
pub updated_at_micros: Option<i64>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AuthStoreSnapshotImportRecord {
pub struct AuthStoreProjectionSyncRecord {
pub imported_user_count: u32,
pub imported_identity_count: u32,
pub imported_refresh_session_count: u32,
@@ -179,7 +179,8 @@ pub(crate) use self::assets::{
map_asset_object_row, map_entity_binding_procedure_result, map_procedure_result,
};
pub(crate) use self::auth::{
map_auth_store_snapshot_import_procedure_result, map_auth_store_snapshot_procedure_result,
map_auth_store_projection_procedure_result, map_auth_store_projection_sync_procedure_result,
map_auth_store_projection_view_input,
};
pub(crate) use self::bark_battle::{
map_bark_battle_draft_config_procedure_result, map_bark_battle_draft_config_row,
@@ -1,42 +1,146 @@
use super::*;
pub(crate) fn map_auth_store_snapshot_procedure_result(
result: AuthStoreSnapshotProcedureResult,
) -> Result<AuthStoreSnapshotRecord, SpacetimeClientError> {
pub(crate) fn map_auth_store_projection_procedure_result(
result: crate::module_bindings::AuthStoreProjectionProcedureResult,
) -> Result<module_auth::AuthStoreProjectionView, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
result
.record
.map(map_auth_store_projection_view)
.ok_or_else(|| SpacetimeClientError::missing_snapshot("认证投影"))
}
pub(crate) fn map_auth_store_projection_sync_procedure_result(
result: crate::module_bindings::AuthStoreProjectionSyncProcedureResult,
) -> Result<AuthStoreProjectionSyncRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let record = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("认证快照"))?;
.ok_or_else(|| SpacetimeClientError::missing_snapshot("认证投影同步结果"))?;
Ok(map_auth_store_snapshot_record(record))
}
pub(crate) fn map_auth_store_snapshot_record(
record: crate::module_bindings::AuthStoreSnapshotRecord,
) -> crate::AuthStoreSnapshotRecord {
crate::AuthStoreSnapshotRecord {
snapshot_json: record.snapshot_json,
updated_at_micros: record.updated_at_micros,
}
}
pub(crate) fn map_auth_store_snapshot_import_procedure_result(
result: AuthStoreSnapshotImportProcedureResult,
) -> Result<AuthStoreSnapshotImportRecord, SpacetimeClientError> {
if !result.ok {
return Err(SpacetimeClientError::procedure_failed(result.error_message));
}
let record = result
.record
.ok_or_else(|| SpacetimeClientError::missing_snapshot("认证快照导入结果"))?;
Ok(AuthStoreSnapshotImportRecord {
Ok(AuthStoreProjectionSyncRecord {
imported_user_count: record.imported_user_count,
imported_identity_count: record.imported_identity_count,
imported_refresh_session_count: record.imported_refresh_session_count,
})
}
pub(crate) fn map_auth_store_projection_view_input(
view: module_auth::AuthStoreProjectionView,
) -> crate::module_bindings::AuthStoreProjectionView {
crate::module_bindings::AuthStoreProjectionView {
updated_at_micros: view.updated_at_micros,
users: view
.users
.into_iter()
.map(|user| crate::module_bindings::AuthStoreProjectionUser {
user_id: user.user_id,
public_user_code: user.public_user_code,
username: user.username,
display_name: user.display_name,
avatar_url: user.avatar_url,
phone_number_masked: user.phone_number_masked,
phone_number_e_164: user.phone_number_e164,
login_method: user.login_method,
binding_status: user.binding_status,
wechat_bound: user.wechat_bound,
password_hash: user.password_hash,
password_login_enabled: user.password_login_enabled,
token_version: user.token_version,
created_at: user.created_at,
})
.collect(),
identities: view
.identities
.into_iter()
.map(
|identity| crate::module_bindings::AuthStoreProjectionIdentity {
identity_id: identity.identity_id,
user_id: identity.user_id,
provider: identity.provider,
provider_uid: identity.provider_uid,
provider_union_id: identity.provider_union_id,
},
)
.collect(),
refresh_sessions: view
.refresh_sessions
.into_iter()
.map(
|session| crate::module_bindings::AuthStoreProjectionRefreshSession {
session_id: session.session_id,
user_id: session.user_id,
refresh_token_hash: session.refresh_token_hash,
issued_by_provider: session.issued_by_provider,
client_info_json: session.client_info_json,
expires_at: session.expires_at,
revoked_at: session.revoked_at,
created_at: session.created_at,
updated_at: session.updated_at,
last_seen_at: session.last_seen_at,
},
)
.collect(),
}
}
fn map_auth_store_projection_view(
view: crate::module_bindings::AuthStoreProjectionView,
) -> module_auth::AuthStoreProjectionView {
module_auth::AuthStoreProjectionView {
updated_at_micros: view.updated_at_micros,
users: view
.users
.into_iter()
.map(|user| module_auth::AuthStoreProjectionUser {
user_id: user.user_id,
public_user_code: user.public_user_code,
username: user.username,
display_name: user.display_name,
avatar_url: user.avatar_url,
phone_number_masked: user.phone_number_masked,
phone_number_e164: user.phone_number_e_164,
login_method: user.login_method,
binding_status: user.binding_status,
wechat_bound: user.wechat_bound,
password_hash: user.password_hash,
password_login_enabled: user.password_login_enabled,
token_version: user.token_version,
created_at: user.created_at,
})
.collect(),
identities: view
.identities
.into_iter()
.map(|identity| module_auth::AuthStoreProjectionIdentity {
identity_id: identity.identity_id,
user_id: identity.user_id,
provider: identity.provider,
provider_uid: identity.provider_uid,
provider_union_id: identity.provider_union_id,
})
.collect(),
refresh_sessions: view
.refresh_sessions
.into_iter()
.map(|session| module_auth::AuthStoreProjectionRefreshSession {
session_id: session.session_id,
user_id: session.user_id,
refresh_token_hash: session.refresh_token_hash,
issued_by_provider: session.issued_by_provider,
client_info_json: session.client_info_json,
expires_at: session.expires_at,
revoked_at: session.revoked_at,
created_at: session.created_at,
updated_at: session.updated_at,
last_seen_at: session.last_seen_at,
})
.collect(),
}
}
@@ -95,15 +95,15 @@ pub mod asset_object_upsert_snapshot_type;
pub mod attach_ai_result_reference_and_return_procedure;
pub mod auth_identity_table;
pub mod auth_identity_type;
pub mod auth_store_projection_identity_type;
pub mod auth_store_projection_meta_table;
pub mod auth_store_projection_meta_type;
pub mod auth_store_snapshot_import_procedure_result_type;
pub mod auth_store_snapshot_import_record_type;
pub mod auth_store_snapshot_procedure_result_type;
pub mod auth_store_snapshot_record_type;
pub mod auth_store_snapshot_table;
pub mod auth_store_snapshot_type;
pub mod auth_store_snapshot_upsert_input_type;
pub mod auth_store_projection_procedure_result_type;
pub mod auth_store_projection_refresh_session_type;
pub mod auth_store_projection_sync_procedure_result_type;
pub mod auth_store_projection_sync_record_type;
pub mod auth_store_projection_user_type;
pub mod auth_store_projection_view_type;
pub mod authenticate_external_api_key_and_return_procedure;
pub mod authorize_database_migration_operator_procedure;
pub mod bark_battle_draft_config_row_type;
@@ -407,7 +407,7 @@ pub mod enqueue_external_generation_job_and_return_procedure;
pub mod ensure_analytics_date_dimension_for_date_reducer;
pub mod equip_inventory_item_input_type;
pub mod execute_custom_world_agent_action_procedure;
pub mod export_auth_store_snapshot_from_tables_procedure;
pub mod export_auth_store_projection_from_tables_procedure;
pub mod export_database_migration_to_file_procedure;
pub mod external_api_key_authenticate_input_type;
pub mod external_api_key_create_input_type;
@@ -502,7 +502,6 @@ pub mod grant_inventory_item_input_type;
pub mod grant_new_user_registration_wallet_reward_procedure;
pub mod grant_player_progression_experience_and_return_procedure;
pub mod grant_player_progression_experience_reducer;
pub mod import_auth_store_snapshot_json_procedure;
pub mod import_database_migration_from_chunks_procedure;
pub mod import_database_migration_from_file_procedure;
pub mod import_database_migration_incremental_from_chunks_procedure;
@@ -1107,6 +1106,7 @@ pub mod submit_square_hole_agent_message_procedure;
pub mod submit_visual_novel_agent_message_procedure;
pub mod swap_puzzle_clear_cards_procedure;
pub mod swap_puzzle_pieces_procedure;
pub mod sync_auth_store_projection_procedure;
pub mod tracking_daily_stat_table;
pub mod tracking_daily_stat_type;
pub mod tracking_event_table;
@@ -1323,15 +1323,15 @@ pub use asset_object_upsert_snapshot_type::AssetObjectUpsertSnapshot;
pub use attach_ai_result_reference_and_return_procedure::attach_ai_result_reference_and_return;
pub use auth_identity_table::*;
pub use auth_identity_type::AuthIdentity;
pub use auth_store_projection_identity_type::AuthStoreProjectionIdentity;
pub use auth_store_projection_meta_table::*;
pub use auth_store_projection_meta_type::AuthStoreProjectionMeta;
pub use auth_store_snapshot_import_procedure_result_type::AuthStoreSnapshotImportProcedureResult;
pub use auth_store_snapshot_import_record_type::AuthStoreSnapshotImportRecord;
pub use auth_store_snapshot_procedure_result_type::AuthStoreSnapshotProcedureResult;
pub use auth_store_snapshot_record_type::AuthStoreSnapshotRecord;
pub use auth_store_snapshot_table::*;
pub use auth_store_snapshot_type::AuthStoreSnapshot;
pub use auth_store_snapshot_upsert_input_type::AuthStoreSnapshotUpsertInput;
pub use auth_store_projection_procedure_result_type::AuthStoreProjectionProcedureResult;
pub use auth_store_projection_refresh_session_type::AuthStoreProjectionRefreshSession;
pub use auth_store_projection_sync_procedure_result_type::AuthStoreProjectionSyncProcedureResult;
pub use auth_store_projection_sync_record_type::AuthStoreProjectionSyncRecord;
pub use auth_store_projection_user_type::AuthStoreProjectionUser;
pub use auth_store_projection_view_type::AuthStoreProjectionView;
pub use authenticate_external_api_key_and_return_procedure::authenticate_external_api_key_and_return;
pub use authorize_database_migration_operator_procedure::authorize_database_migration_operator;
pub use bark_battle_draft_config_row_type::BarkBattleDraftConfigRow;
@@ -1635,7 +1635,7 @@ pub use enqueue_external_generation_job_and_return_procedure::enqueue_external_g
pub use ensure_analytics_date_dimension_for_date_reducer::ensure_analytics_date_dimension_for_date;
pub use equip_inventory_item_input_type::EquipInventoryItemInput;
pub use execute_custom_world_agent_action_procedure::execute_custom_world_agent_action;
pub use export_auth_store_snapshot_from_tables_procedure::export_auth_store_snapshot_from_tables;
pub use export_auth_store_projection_from_tables_procedure::export_auth_store_projection_from_tables;
pub use export_database_migration_to_file_procedure::export_database_migration_to_file;
pub use external_api_key_authenticate_input_type::ExternalApiKeyAuthenticateInput;
pub use external_api_key_create_input_type::ExternalApiKeyCreateInput;
@@ -1730,7 +1730,6 @@ pub use grant_inventory_item_input_type::GrantInventoryItemInput;
pub use grant_new_user_registration_wallet_reward_procedure::grant_new_user_registration_wallet_reward;
pub use grant_player_progression_experience_and_return_procedure::grant_player_progression_experience_and_return;
pub use grant_player_progression_experience_reducer::grant_player_progression_experience;
pub use import_auth_store_snapshot_json_procedure::import_auth_store_snapshot_json;
pub use import_database_migration_from_chunks_procedure::import_database_migration_from_chunks;
pub use import_database_migration_from_file_procedure::import_database_migration_from_file;
pub use import_database_migration_incremental_from_chunks_procedure::import_database_migration_incremental_from_chunks;
@@ -2335,6 +2334,7 @@ pub use submit_square_hole_agent_message_procedure::submit_square_hole_agent_mes
pub use submit_visual_novel_agent_message_procedure::submit_visual_novel_agent_message;
pub use swap_puzzle_clear_cards_procedure::swap_puzzle_clear_cards;
pub use swap_puzzle_pieces_procedure::swap_puzzle_pieces;
pub use sync_auth_store_projection_procedure::sync_auth_store_projection;
pub use tracking_daily_stat_table::*;
pub use tracking_daily_stat_type::TrackingDailyStat;
pub use tracking_event_table::*;
@@ -2745,7 +2745,6 @@ pub struct DbUpdate {
asset_object: __sdk::TableUpdate<AssetObject>,
auth_identity: __sdk::TableUpdate<AuthIdentity>,
auth_store_projection_meta: __sdk::TableUpdate<AuthStoreProjectionMeta>,
auth_store_snapshot: __sdk::TableUpdate<AuthStoreSnapshot>,
bark_battle_draft_config: __sdk::TableUpdate<BarkBattleDraftConfigRow>,
bark_battle_gallery_view: __sdk::TableUpdate<BarkBattleGalleryViewRow>,
bark_battle_leaderboard_entry: __sdk::TableUpdate<BarkBattleLeaderboardEntryRow>,
@@ -2902,9 +2901,6 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate {
"auth_store_projection_meta" => db_update.auth_store_projection_meta.append(
auth_store_projection_meta_table::parse_table_update(table_update)?,
),
"auth_store_snapshot" => db_update
.auth_store_snapshot
.append(auth_store_snapshot_table::parse_table_update(table_update)?),
"bark_battle_draft_config" => db_update.bark_battle_draft_config.append(
bark_battle_draft_config_table::parse_table_update(table_update)?,
),
@@ -3333,12 +3329,6 @@ impl __sdk::DbUpdate for DbUpdate {
&self.auth_store_projection_meta,
)
.with_updates_by_pk(|row| &row.meta_id);
diff.auth_store_snapshot = cache
.apply_diff_to_table::<AuthStoreSnapshot>(
"auth_store_snapshot",
&self.auth_store_snapshot,
)
.with_updates_by_pk(|row| &row.snapshot_id);
diff.bark_battle_draft_config = cache
.apply_diff_to_table::<BarkBattleDraftConfigRow>(
"bark_battle_draft_config",
@@ -3966,9 +3956,6 @@ impl __sdk::DbUpdate for DbUpdate {
"auth_store_projection_meta" => db_update
.auth_store_projection_meta
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"auth_store_snapshot" => db_update
.auth_store_snapshot
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"bark_battle_draft_config" => db_update
.bark_battle_draft_config
.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
@@ -4360,9 +4347,6 @@ impl __sdk::DbUpdate for DbUpdate {
"auth_store_projection_meta" => db_update
.auth_store_projection_meta
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"auth_store_snapshot" => db_update
.auth_store_snapshot
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"bark_battle_draft_config" => db_update
.bark_battle_draft_config
.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
@@ -4734,7 +4718,6 @@ pub struct AppliedDiff<'r> {
asset_object: __sdk::TableAppliedDiff<'r, AssetObject>,
auth_identity: __sdk::TableAppliedDiff<'r, AuthIdentity>,
auth_store_projection_meta: __sdk::TableAppliedDiff<'r, AuthStoreProjectionMeta>,
auth_store_snapshot: __sdk::TableAppliedDiff<'r, AuthStoreSnapshot>,
bark_battle_draft_config: __sdk::TableAppliedDiff<'r, BarkBattleDraftConfigRow>,
bark_battle_gallery_view: __sdk::TableAppliedDiff<'r, BarkBattleGalleryViewRow>,
bark_battle_leaderboard_entry: __sdk::TableAppliedDiff<'r, BarkBattleLeaderboardEntryRow>,
@@ -4913,11 +4896,6 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> {
&self.auth_store_projection_meta,
event,
);
callbacks.invoke_table_row_callbacks::<AuthStoreSnapshot>(
"auth_store_snapshot",
&self.auth_store_snapshot,
event,
);
callbacks.invoke_table_row_callbacks::<BarkBattleDraftConfigRow>(
"bark_battle_draft_config",
&self.bark_battle_draft_config,
@@ -6152,7 +6130,6 @@ impl __sdk::SpacetimeModule for RemoteModule {
asset_object_table::register_table(client_cache);
auth_identity_table::register_table(client_cache);
auth_store_projection_meta_table::register_table(client_cache);
auth_store_snapshot_table::register_table(client_cache);
bark_battle_draft_config_table::register_table(client_cache);
bark_battle_gallery_view_table::register_table(client_cache);
bark_battle_leaderboard_entry_table::register_table(client_cache);
@@ -6281,7 +6258,6 @@ impl __sdk::SpacetimeModule for RemoteModule {
"asset_object",
"auth_identity",
"auth_store_projection_meta",
"auth_store_snapshot",
"bark_battle_draft_config",
"bark_battle_gallery_view",
"bark_battle_leaderboard_entry",
@@ -6,11 +6,14 @@ use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreSnapshotUpsertInput {
pub snapshot_json: String,
pub updated_at_micros: i64,
pub struct AuthStoreProjectionIdentity {
pub identity_id: String,
pub user_id: String,
pub provider: String,
pub provider_uid: String,
pub provider_union_id: Option<String>,
}
impl __sdk::InModule for AuthStoreSnapshotUpsertInput {
impl __sdk::InModule for AuthStoreProjectionIdentity {
type Module = super::RemoteModule;
}
@@ -4,16 +4,16 @@
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
use super::auth_store_snapshot_record_type::AuthStoreSnapshotRecord;
use super::auth_store_projection_view_type::AuthStoreProjectionView;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreSnapshotProcedureResult {
pub struct AuthStoreProjectionProcedureResult {
pub ok: bool,
pub record: Option<AuthStoreSnapshotRecord>,
pub record: Option<AuthStoreProjectionView>,
pub error_message: Option<String>,
}
impl __sdk::InModule for AuthStoreSnapshotProcedureResult {
impl __sdk::InModule for AuthStoreProjectionProcedureResult {
type Module = super::RemoteModule;
}
@@ -0,0 +1,24 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreProjectionRefreshSession {
pub session_id: String,
pub user_id: String,
pub refresh_token_hash: String,
pub issued_by_provider: String,
pub client_info_json: String,
pub expires_at: String,
pub revoked_at: Option<String>,
pub created_at: String,
pub updated_at: String,
pub last_seen_at: String,
}
impl __sdk::InModule for AuthStoreProjectionRefreshSession {
type Module = super::RemoteModule;
}
@@ -4,16 +4,16 @@
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
use super::auth_store_snapshot_import_record_type::AuthStoreSnapshotImportRecord;
use super::auth_store_projection_sync_record_type::AuthStoreProjectionSyncRecord;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreSnapshotImportProcedureResult {
pub struct AuthStoreProjectionSyncProcedureResult {
pub ok: bool,
pub record: Option<AuthStoreSnapshotImportRecord>,
pub record: Option<AuthStoreProjectionSyncRecord>,
pub error_message: Option<String>,
}
impl __sdk::InModule for AuthStoreSnapshotImportProcedureResult {
impl __sdk::InModule for AuthStoreProjectionSyncProcedureResult {
type Module = super::RemoteModule;
}
@@ -6,12 +6,12 @@ use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreSnapshotImportRecord {
pub struct AuthStoreProjectionSyncRecord {
pub imported_user_count: u32,
pub imported_identity_count: u32,
pub imported_refresh_session_count: u32,
}
impl __sdk::InModule for AuthStoreSnapshotImportRecord {
impl __sdk::InModule for AuthStoreProjectionSyncRecord {
type Module = super::RemoteModule;
}
@@ -0,0 +1,28 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreProjectionUser {
pub user_id: String,
pub public_user_code: String,
pub username: String,
pub display_name: String,
pub avatar_url: Option<String>,
pub phone_number_masked: Option<String>,
pub phone_number_e_164: Option<String>,
pub login_method: String,
pub binding_status: String,
pub wechat_bound: bool,
pub password_hash: String,
pub password_login_enabled: bool,
pub token_version: u64,
pub created_at: String,
}
impl __sdk::InModule for AuthStoreProjectionUser {
type Module = super::RemoteModule;
}
@@ -0,0 +1,22 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
use super::auth_store_projection_identity_type::AuthStoreProjectionIdentity;
use super::auth_store_projection_refresh_session_type::AuthStoreProjectionRefreshSession;
use super::auth_store_projection_user_type::AuthStoreProjectionUser;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreProjectionView {
pub updated_at_micros: i64,
pub users: Vec<AuthStoreProjectionUser>,
pub identities: Vec<AuthStoreProjectionIdentity>,
pub refresh_sessions: Vec<AuthStoreProjectionRefreshSession>,
}
impl __sdk::InModule for AuthStoreProjectionView {
type Module = super::RemoteModule;
}

Some files were not shown because too many files have changed in this diff Show More