From 04288d4a40ccee004f5b72b2dcad2126829a1e6f Mon Sep 17 00:00:00 2001 From: kdletters Date: Fri, 24 Apr 2026 15:35:04 +0800 Subject: [PATCH 1/2] chore: update spacetime dev scripts --- ...ND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md | 32 ++++---- scripts/deploy-rust-remote.sh | 6 +- scripts/dev-rust-stack.sh | 75 ++++++++++++++++--- scripts/spacetime-logs-local.sh | 9 ++- 4 files changed, 91 insertions(+), 31 deletions(-) diff --git a/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md b/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md index 39a15882..a2904310 100644 --- a/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md +++ b/docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md @@ -1,4 +1,4 @@ -# Rust 本地联调与远端发布脚本方案 +# Rust 本地联调与远端发布脚本方案 日期:`2026-04-22` @@ -32,12 +32,13 @@ npm run dev:rust 默认流程: 1. 检查 `cargo`、`node` 与 `spacetime` CLI。 -2. 启动 `spacetime --root-dir=server-rs/.spacetimedb/local start --edition standalone --listen-addr 127.0.0.1:3101`,确保本地数据库与 SpacetimeDB 内部日志不会落到开发者全局目录。 -3. 等待 `spacetime server ping http://127.0.0.1:3101` 可用。 -4. 执行 `spacetime publish <本地数据库名> --server http://127.0.0.1:3101 --module-path server-rs/crates/spacetime-module --yes`。 -5. 注入 `GENARRATIVE_API_*` 与 `GENARRATIVE_SPACETIME_*` 后启动 `cargo run -p api-server`;直接运行 `api-server` 时,如未显式设置 `GENARRATIVE_SPACETIME_DATABASE`,服务端也会向上查找 `spacetime.local.json` 作为本地默认库名。 -6. 注入 `GENARRATIVE_BACKEND_STACK=rust`、`RUST_SERVER_TARGET`、`GENARRATIVE_RUNTIME_SERVER_TARGET` 后启动 Vite。 -7. 任一子进程退出时,脚本回收其余子进程。 +2. Windows Git Bash 下如 `server-rs/.spacetimedb/local/bin/current/spacetimedb-cli.exe` 不存在,先把本机 `spacetime` 所在安装目录的 `bin/` 与 `spacetime.exe` 同步到 `server-rs/.spacetimedb/local/`。 +3. 启动 `spacetime --root-dir=server-rs/.spacetimedb/local start --edition standalone --listen-addr 127.0.0.1:3101`,确保本地数据库与 SpacetimeDB 内部日志不会落到开发者全局目录。 +4. 等待 `spacetime --root-dir=server-rs/.spacetimedb/local server ping http://127.0.0.1:3101` 可用。 +5. 执行 `spacetime --root-dir=server-rs/.spacetimedb/local publish <本地数据库名> --server http://127.0.0.1:3101 --module-path server-rs/crates/spacetime-module -c=on-conflict --yes`,确保 publish 的签名身份与 standalone 的本地控制库一致,并在当前开发阶段允许新版模块表结构变化且发生 schema 冲突时清除旧模块数据。 +6. 注入 `GENARRATIVE_API_*` 与 `GENARRATIVE_SPACETIME_*` 后启动 `cargo run -p api-server`;直接运行 `api-server` 时,如未显式设置 `GENARRATIVE_SPACETIME_DATABASE`,服务端也会向上查找 `spacetime.local.json` 作为本地默认库名。 +7. 注入 `GENARRATIVE_BACKEND_STACK=rust`、`RUST_SERVER_TARGET`、`GENARRATIVE_RUNTIME_SERVER_TARGET` 后启动 Vite。 +8. 任一子进程退出时,脚本回收其余子进程。 Vite 代理覆盖范围: @@ -47,10 +48,11 @@ Vite 代理覆盖范围: 安全边界: -1. 默认不执行 `--clear-database`。 -2. 只有显式传入 `--clear-database` 才允许清库重发。 +1. 当前开发阶段默认执行 `-c=on-conflict`,允许本地开发库在表结构变化时清除旧模块数据后重发。 +2. 只有显式传入 `--preserve-database` 时,才跳过 `-c=on-conflict` 并保留现有数据。 3. 如需要复用已经启动的 SpacetimeDB,可传 `--skip-spacetime`。 4. 如只想启动进程不发布模块,可传 `--skip-publish`。 +5. 后续进入正式版本前,涉及表结构变化时必须在开发阶段补齐迁移表与迁移函数,不能依赖清库发布作为正式升级策略。 常用示例: @@ -59,7 +61,7 @@ npm run dev:rust ./scripts/dev-rust-stack.sh ./scripts/dev-rust-stack.sh --api-port 8090 --spacetime-port 3110 --database genarrative-dev ./scripts/dev-rust-stack.sh --skip-spacetime --skip-publish -./scripts/dev-rust-stack.sh --clear-database +./scripts/dev-rust-stack.sh --preserve-database ``` 日志提取: @@ -72,7 +74,7 @@ npm run dev:rust:logs -- --follow 日志提取规则: -1. SpacetimeDB 模块日志以 `spacetime logs ` 为唯一提取入口,脚本不直接读取内部日志文件结构。 +1. SpacetimeDB 模块日志以 `spacetime --root-dir=server-rs/.spacetimedb/local logs ` 为唯一提取入口,脚本不直接读取内部日志文件结构。 2. 默认读取 `spacetime.local.json` 的 `database` 字段,默认 server 为 `http://127.0.0.1:3101`。 3. 默认输出到 `logs/spacetime/-.log`,并通过 `tee` 同步显示在终端。 4. `--follow` 仅用于本地追踪,会持续追加到同一个输出文件;停止时用 `Ctrl+C`。 @@ -80,7 +82,7 @@ npm run dev:rust:logs -- --follow 联调排错补充: 1. 如果首页公开广场出现 `上游服务请求失败`,优先检查 `api-server` 错误详情里的 `ws://.../v1/database//subscribe` 是否指向了未发布的库。 -2. `spacetime list --server http://127.0.0.1:3101` 应能看到 `spacetime.local.json` 中的库名;若没有,执行 `spacetime publish <本地数据库名> --server http://127.0.0.1:3101 --module-path server-rs/crates/spacetime-module --yes`。 +2. `spacetime --root-dir=server-rs/.spacetimedb/local list --server http://127.0.0.1:3101` 应能看到 `spacetime.local.json` 中的库名;若没有,执行 `spacetime --root-dir=server-rs/.spacetimedb/local publish <本地数据库名> --server http://127.0.0.1:3101 --module-path server-rs/crates/spacetime-module -c=on-conflict --yes`。 3. 发布库名与 `GENARRATIVE_SPACETIME_DATABASE` 不一致时,`/api/runtime/custom-world-gallery` 会从 Rust `api-server` 返回 `502`,前端首页只能展示空态或错误提示,无法自行修复。 ## 3. Ubuntu 发布包脚本 @@ -108,7 +110,7 @@ npm run deploy:rust:remote 5. 执行 `cargo build -p spacetime-module --release --target wasm32-unknown-unknown --manifest-path server-rs/Cargo.toml`,并把 `spacetime_module.wasm` 复制到目标目录。 6. 把仓库根目录的 `.env` 与 `.env.local` 分别复制到目标目录根部和目标目录的 `web/` 下。 7. 在目标目录写入 `web-server.mjs`,用于托管 `web/` 并把 `/api/*`、`/generated-*`、`/healthz` 反代到本包内的 `api-server`。 -8. 在目标目录写入 `start.sh` 与 `stop.sh`;`start.sh` 会先加载发布目录根部的 `.env`、`.env.local`,再回退到构建时通过 `--database`、`--api-port`、`--web-port`、`--spacetime-host`、`--spacetime-port` 写入的默认值,并默认导出 `NO_COLOR=1` 与 `CARGO_TERM_COLOR=never`,避免 ANSI 控制码写入日志文件;如果以 `--clear-database` 启动,则内部 `spacetime publish` 会追加 `-c always`。 +8. 在目标目录写入 `start.sh` 与 `stop.sh`;`start.sh` 会先加载发布目录根部的 `.env`、`.env.local`,再回退到构建时通过 `--database`、`--api-port`、`--web-port`、`--spacetime-host`、`--spacetime-port` 写入的默认值,并默认导出 `NO_COLOR=1` 与 `CARGO_TERM_COLOR=never`,避免 ANSI 控制码写入日志文件;如果以 `--clear-database` 启动,则内部 `spacetime publish` 会追加 `-c=on-conflict`,仅在 schema 冲突时删除旧模块数据。 9. 默认执行 `scp -r -i ~\.ssh\dsk.pem build/ ubuntu@82.157.175.59:/home/ubuntu/genarrative/` 上传发布包。 发布包结构: @@ -150,8 +152,8 @@ cd build/ 1. 构建脚本会把仓库根目录已有的 `.env`、`.env.local` 一并复制进发布包,因此运行前必须确认这些文件内容适合被带入目标环境。 2. 如果仓库根目录不存在 `.env` 或 `.env.local`,脚本会打印跳过日志,但不会因此失败;此时 `start.sh` 仅使用构建时写入的默认值与运行时显式传入的环境变量。 -3. `start.sh` 默认不清空 SpacetimeDB;只有显式执行 `./start.sh --clear-database` 才允许清库重发。 -4. `start.sh` 使用 `spacetime publish --bin-path spacetime_module.wasm --yes` 发布当前包内 wasm;清库模式下会追加 `-c always`。 +3. `start.sh` 默认不追加清理参数;只有显式执行 `./start.sh --clear-database` 才追加 `-c=on-conflict`,在 schema 冲突时清理旧模块数据后重发。 +4. `start.sh` 使用 `spacetime publish --bin-path spacetime_module.wasm --yes` 发布当前包内 wasm;清库模式下会追加 `-c=on-conflict`,仅在 schema 冲突时删除旧模块数据。 5. 当前脚本是单目录进程启动方案,不替代生产 systemd、Nginx、TLS、日志轮转与守护进程配置。 6. 如只需要本地生成发布包,可传 `--skip-upload` 跳过默认 scp 上传。 diff --git a/scripts/deploy-rust-remote.sh b/scripts/deploy-rust-remote.sh index 08feece4..49a33fee 100644 --- a/scripts/deploy-rust-remote.sh +++ b/scripts/deploy-rust-remote.sh @@ -448,7 +448,7 @@ usage() { 说明: 1. 启动当前发布包内的静态网站、SpacetimeDB 与 api-server。 2. 默认发布 spacetime_module.wasm 到 GENARRATIVE_SPACETIME_DATABASE,但不清库。 - 3. 只有显式传入 --clear-database 时才允许清空数据库重发。 + 3. 只有显式传入 --clear-database 时才会在 schema 冲突时清理旧模块数据后重发。 EOF } @@ -550,8 +550,8 @@ PUBLISH_ARGS=( ) if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then - # 按当前 SpacetimeDB CLI 约定使用 -c,等价于 --delete-data always。 - PUBLISH_ARGS+=(-c) + # 发布包清库模式只在 schema 冲突时删除旧模块数据,避免无冲突升级误清数据。 + PUBLISH_ARGS+=(-c=on-conflict) fi echo "[start] 发布 SpacetimeDB wasm: ${SPACETIME_DATABASE}" diff --git a/scripts/dev-rust-stack.sh b/scripts/dev-rust-stack.sh index 64178ad1..1e70dda8 100644 --- a/scripts/dev-rust-stack.sh +++ b/scripts/dev-rust-stack.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env bash set -euo pipefail @@ -8,13 +8,13 @@ usage() { npm run dev:rust ./scripts/dev-rust-stack.sh --api-port 8090 --spacetime-port 3110 ./scripts/dev-rust-stack.sh --skip-spacetime --skip-publish - ./scripts/dev-rust-stack.sh --clear-database + ./scripts/dev-rust-stack.sh --preserve-database npm run dev:rust:logs -- --follow 说明: 1. 默认同时启动 SpacetimeDB standalone、Rust api-server 与 Vite 前端。 - 2. 默认会 publish server-rs/crates/spacetime-module,但不会清空数据库。 - 3. 只有显式传入 --clear-database 时,才会追加 spacetime publish --clear-database。 + 2. 当前开发阶段默认 publish server-rs/crates/spacetime-module 时追加 -c=on-conflict 在结构冲突时清理旧模块数据。 + 3. 只有显式传入 --preserve-database 时,才会跳过 -c=on-conflict。 4. SpacetimeDB 默认使用 server-rs/.spacetimedb/local 作为本地数据与日志目录。 EOF } @@ -67,7 +67,8 @@ cleanup() { wait_for_spacetime() { local server="$1" local timeout_seconds="$2" - local process_pid="${3:-}" + local root_dir="$3" + local process_pid="${4:-}" local deadline=$((SECONDS + timeout_seconds)) while ((SECONDS < deadline)); do @@ -76,7 +77,7 @@ wait_for_spacetime() { exit 1 fi - if spacetime server ping "${server}" >/dev/null 2>&1; then + if spacetime --root-dir="${root_dir}" server ping "${server}" >/dev/null 2>&1; then return fi @@ -87,6 +88,51 @@ wait_for_spacetime() { exit 1 } +sync_local_spacetime_install() { + local root_dir="$1" + + # SpacetimeDB standalone 会在 --root-dir 下回调 bin/current/spacetimedb-cli.exe; + # Windows 本地开发使用工程内 root-dir 时,需要把用户级安装目录同步进来。 + if [[ "${OSTYPE:-}" != msys* && "${OSTYPE:-}" != cygwin* ]]; then + return + fi + + local target_cli="${root_dir}/bin/current/spacetimedb-cli.exe" + if [[ -f "${target_cli}" ]]; then + return + fi + + local spacetime_command + spacetime_command="$(command -v spacetime || true)" + if [[ -z "${spacetime_command}" ]]; then + return + fi + + local install_dir + install_dir="$(cd -- "$(dirname -- "${spacetime_command}")" && pwd)" + if [[ ! -d "${install_dir}/bin" ]]; then + return + fi + + echo "[dev:rust] 同步本机 SpacetimeDB 安装到 ${root_dir}" + mkdir -p "${root_dir}" + cp -a "${install_dir}/bin" "${root_dir}/" + if [[ -f "${install_dir}/spacetime.exe" ]]; then + cp -f "${install_dir}/spacetime.exe" "${root_dir}/spacetime.exe" + fi + + # Git Bash 复制 Windows junction 时可能不会生成可执行的 current 目录; + # 若 current 缺失,则用最新版本目录复制出一个真实目录,满足 standalone 回调路径。 + if [[ ! -f "${target_cli}" ]]; then + local version_dir + version_dir="$(find "${root_dir}/bin" -mindepth 1 -maxdepth 1 -type d ! -name current | sort -V | tail -n 1)" + if [[ -n "${version_dir}" && -f "${version_dir}/spacetimedb-cli.exe" ]]; then + rm -rf "${root_dir}/bin/current" + cp -a "${version_dir}" "${root_dir}/bin/current" + fi + fi +} + SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" SERVER_RS_DIR="${REPO_ROOT}/server-rs" @@ -106,7 +152,7 @@ API_LOG="info,tower_http=info" SPACETIME_TIMEOUT_SECONDS="60" SKIP_SPACETIME=0 SKIP_PUBLISH=0 -CLEAR_DATABASE=0 +PRESERVE_DATABASE=0 PIDS=() NAMES=() @@ -186,7 +232,11 @@ while [[ $# -gt 0 ]]; do shift ;; --clear-database) - CLEAR_DATABASE=1 + PRESERVE_DATABASE=0 + shift + ;; + --preserve-database) + PRESERVE_DATABASE=1 shift ;; *) @@ -242,6 +292,7 @@ echo "[dev:rust] spacetime root: ${SPACETIME_ROOT_DIR}" if [[ "${SKIP_SPACETIME}" -ne 1 ]]; then mkdir -p "${SPACETIME_ROOT_DIR}" + sync_local_spacetime_install "${SPACETIME_ROOT_DIR}" echo "[dev:rust] 启动 spacetimedb" ( cd "${SERVER_RS_DIR}" @@ -257,7 +308,7 @@ fi if [[ "${SKIP_PUBLISH}" -ne 1 ]]; then echo "[dev:rust] 等待 SpacetimeDB 就绪" - wait_for_spacetime "${SPACETIME_SERVER}" "${SPACETIME_TIMEOUT_SECONDS}" "${PIDS[0]:-}" + wait_for_spacetime "${SPACETIME_SERVER}" "${SPACETIME_TIMEOUT_SECONDS}" "${SPACETIME_ROOT_DIR}" "${PIDS[0]:-}" PUBLISH_ARGS=( publish @@ -266,14 +317,14 @@ if [[ "${SKIP_PUBLISH}" -ne 1 ]]; then --module-path "${MODULE_PATH}" ) - if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then - PUBLISH_ARGS+=(--clear-database) + if [[ "${PRESERVE_DATABASE}" -ne 1 ]]; then + PUBLISH_ARGS+=(-c=on-conflict) fi PUBLISH_ARGS+=(--yes) echo "[dev:rust] 发布 SpacetimeDB 模块: ${DATABASE}" - spacetime "${PUBLISH_ARGS[@]}" + spacetime --root-dir="${SPACETIME_ROOT_DIR}" "${PUBLISH_ARGS[@]}" fi echo "[dev:rust] 启动 api-server" diff --git a/scripts/spacetime-logs-local.sh b/scripts/spacetime-logs-local.sh index 4a4b9046..b7528570 100644 --- a/scripts/spacetime-logs-local.sh +++ b/scripts/spacetime-logs-local.sh @@ -13,6 +13,7 @@ usage() { 1. 从本地 SpacetimeDB 通过 spacetime logs 提取模块日志到本地文件。 2. 默认读取 spacetime.local.json 的 database 字段,默认 server 为 http://127.0.0.1:3101。 3. 默认输出到 logs/spacetime/-.log;--follow 会持续追加并同步写到终端。 + 4. 默认使用 server-rs/.spacetimedb/local 作为 spacetime CLI root,保持本地身份与 standalone 一致。 EOF } @@ -51,6 +52,7 @@ REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" DATABASE="" SPACETIME_SERVER="http://127.0.0.1:3101" +SPACETIME_ROOT_DIR="${REPO_ROOT}/server-rs/.spacetimedb/local" LINES="200" OUTPUT="" FOLLOW=0 @@ -69,6 +71,10 @@ while [[ $# -gt 0 ]]; do SPACETIME_SERVER="${2:?缺少 --server 的值}" shift 2 ;; + --spacetime-root-dir) + SPACETIME_ROOT_DIR="${2:?缺少 --spacetime-root-dir 的值}" + shift 2 + ;; --lines|-n) LINES="${2:?缺少 --lines 的值}" shift 2 @@ -117,6 +123,7 @@ fi echo "[stdb:logs] database: ${DATABASE}" echo "[stdb:logs] server: ${SPACETIME_SERVER}" +echo "[stdb:logs] spacetime root: ${SPACETIME_ROOT_DIR}" echo "[stdb:logs] output: ${OUTPUT}" -spacetime "${ARGS[@]}" | tee -a "${OUTPUT}" +spacetime --root-dir="${SPACETIME_ROOT_DIR}" "${ARGS[@]}" | tee -a "${OUTPUT}" From 4e1c0462a434902c54f7f825561cb4bf24f9cba2 Mon Sep 17 00:00:00 2001 From: kdletters Date: Fri, 24 Apr 2026 16:09:20 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=8C=81=E4=B9=85=E5=8C=96=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E7=8A=B6=E6=80=81=E5=88=B0=20SpacetimeDB=20=E6=AD=A3?= =?UTF-8?q?=E5=BC=8F=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...FORMAL_TABLE_RECOVERY_STAGE3_2026-04-24.md | 52 + ...ACETIMEDB_TABLE_SPLIT_STAGE2_2026-04-24.md | 97 + server-rs/crates/api-server/src/state.rs | 25 +- server-rs/crates/spacetime-client/src/ai.rs | 29 +- .../crates/spacetime-client/src/assets.rs | 7 +- server-rs/crates/spacetime-client/src/auth.rs | 33 +- .../crates/spacetime-client/src/big_fish.rs | 41 +- .../crates/spacetime-client/src/combat.rs | 16 +- .../spacetime-client/src/custom_world.rs | 24 +- .../crates/spacetime-client/src/inventory.rs | 8 +- server-rs/crates/spacetime-client/src/lib.rs | 6717 +---------------- .../crates/spacetime-client/src/mapper.rs | 913 ++- .../module_bindings/auth_identity_table.rs | 163 + .../src/module_bindings/auth_identity_type.rs | 83 + ...e_snapshot_import_procedure_result_type.rs | 26 + .../auth_store_snapshot_import_record_type.rs | 25 + ...th_store_snapshot_from_tables_procedure.rs | 53 + .../import_auth_store_snapshot_procedure.rs | 53 + .../src/module_bindings/mod.rs | 86 +- .../module_bindings/refresh_session_table.rs | 163 + .../module_bindings/refresh_session_type.rs | 91 + .../rpg_agent_operation_type_type.rs | 4 + .../src/module_bindings/user_account_table.rs | 163 + .../src/module_bindings/user_account_type.rs | 97 + server-rs/crates/spacetime-client/src/npc.rs | 7 +- .../crates/spacetime-client/src/puzzle.rs | 20 +- .../crates/spacetime-client/src/runtime.rs | 130 +- .../crates/spacetime-client/src/story.rs | 53 +- server-rs/crates/spacetime-module/src/auth.rs | 433 ++ 29 files changed, 2271 insertions(+), 7341 deletions(-) create mode 100644 docs/technical/AUTH_SPACETIMEDB_FORMAL_TABLE_RECOVERY_STAGE3_2026-04-24.md create mode 100644 docs/technical/AUTH_SPACETIMEDB_TABLE_SPLIT_STAGE2_2026-04-24.md create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/auth_identity_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/auth_identity_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/auth_store_snapshot_import_procedure_result_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/auth_store_snapshot_import_record_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_snapshot_from_tables_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/import_auth_store_snapshot_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/refresh_session_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/refresh_session_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/user_account_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/user_account_type.rs diff --git a/docs/technical/AUTH_SPACETIMEDB_FORMAL_TABLE_RECOVERY_STAGE3_2026-04-24.md b/docs/technical/AUTH_SPACETIMEDB_FORMAL_TABLE_RECOVERY_STAGE3_2026-04-24.md new file mode 100644 index 00000000..f41a7127 --- /dev/null +++ b/docs/technical/AUTH_SPACETIMEDB_FORMAL_TABLE_RECOVERY_STAGE3_2026-04-24.md @@ -0,0 +1,52 @@ +# Auth SpacetimeDB 正式表恢复 Stage 3 + +## 1. 阶段目标 + +本阶段把认证持久化从“只依赖整包快照恢复”推进到“正式认证表优先恢复”。 + +落地口径: +- `user_account`、`auth_identity`、`refresh_session` 作为 SpacetimeDB 中的正式认证持久化表。 +- API 启动时优先从正式表导出兼容 `module-auth` 的认证快照,再恢复到内存认证服务。 +- 运行期认证变更仍先复用现有 `module-auth` 逻辑生成一致快照,随后同步快照并导入正式表,保证正式表与快照一致。 +- 本阶段不重写登录、刷新、登出内部业务规则,避免在 JWT、refresh rotation、微信绑定合并等复杂语义中引入行为漂移。 + +## 2. 非目标 + +- 不在本阶段把 `PasswordEntryService`、`PhoneAuthService`、`RefreshSessionService` 改造成直接调用 SpacetimeDB reducer。 +- 不在前端增加认证规则说明文案。 +- 不删除 Stage 1 快照表;快照表继续作为导入载体与回滚兜底。 + +## 3. 运行流程 + +### 3.1 启动恢复 + +1. API 调用 `export_auth_store_snapshot_from_tables`。 +2. 若正式表已有用户、身份或会话数据,则返回兼容 `module-auth` 的 JSON 快照。 +3. API 用 `InMemoryAuthStore::from_snapshot_json` 恢复认证服务。 +4. 若正式表为空或调用失败,则回退到 Stage 1 的 `auth_store_snapshot`。 +5. 若 Stage 1 也不可用,则回退本地 JSON 热修复文件。 + +### 3.2 运行期同步 + +1. 登录、刷新、登出等路径继续调用当前内存认证服务。 +2. 每次认证状态变更后调用 `upsert_auth_store_snapshot`。 +3. 快照写入成功后调用 `import_auth_store_snapshot`,覆盖导入正式表。 +4. 导入失败时返回错误,避免用户误以为状态已经持久化。 + +## 4. 数据重建规则 + +- `users_by_username` 由 `user_account.username` 作为 key 重建。 +- `phone_to_user_id` 由 provider 为 `phone` 的 `auth_identity` 重建。 +- `wechat_identity_by_provider_uid` 由 provider 为 `wechat` 的 `auth_identity` 重建。 +- `user_id_by_provider_union_id` 由微信身份中非空 `provider_union_id` 重建。 +- `sessions_by_id` 由 `refresh_session.session_id` 重建。 +- `session_id_by_refresh_token_hash` 由 `refresh_session.refresh_token_hash` 重建。 +- `next_user_id` 取现有 `user_id` 中 `user_数字` 的最大值加一,若不存在则为 1。 + +## 5. 完成定义 + +- SpacetimeDB 模块能 wasm 编译。 +- Rust bindings 已重新生成并包含正式表导出 procedure。 +- `spacetime-client` 暴露正式表导出 facade。 +- `api-server` 启动恢复优先正式表,认证变更同步后导入正式表。 +- `module-auth` 测试保持通过。 diff --git a/docs/technical/AUTH_SPACETIMEDB_TABLE_SPLIT_STAGE2_2026-04-24.md b/docs/technical/AUTH_SPACETIMEDB_TABLE_SPLIT_STAGE2_2026-04-24.md new file mode 100644 index 00000000..7a3a4cb4 --- /dev/null +++ b/docs/technical/AUTH_SPACETIMEDB_TABLE_SPLIT_STAGE2_2026-04-24.md @@ -0,0 +1,97 @@ +# Auth SpacetimeDB 拆表 Stage 2 + +日期:`2026-04-24` + +## 1. 阶段目标 + +Stage 1 已把 Rust 鉴权快照同步到 SpacetimeDB 的 `auth_store_snapshot` 表。本阶段继续把该快照导入正式认证表,建立后续运行时细粒度读写的表结构基础。 + +本阶段落地范围: + +1. 新增 `user_account` 表。 +2. 新增 `auth_identity` 表。 +3. 新增 `refresh_session` 表。 +4. 新增 `import_auth_store_snapshot` procedure,把当前 `auth_store_snapshot.snapshot_json` 拆入三张表。 +5. 保留 Stage 1 快照表作为导入来源与回滚备份。 + +## 2. 非目标 + +本阶段不立即把 `api-server` 的登录、refresh、logout 写入切换到细粒度 reducer。原因是要避免同时改动认证业务语义、导入逻辑和运行时写路径。 + +运行时切换放到 Stage 3: + +1. `POST /api/auth/refresh` 改写 `refresh_session` 表。 +2. 登录成功写 `user_account/auth_identity/refresh_session`。 +3. `logout/logout-all/revoke-session` 改写细粒度表。 +4. `auth_store_snapshot` 退化为迁移备份。 + +## 3. 表设计落地口径 + +### 3.1 `user_account` + +字段先覆盖当前 `module-auth` 快照可提供的账号主数据: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| `user_id` | `String` | 主键。 | +| `public_user_code` | `String` | 公开叙世号。 | +| `username` | `String` | 当前账号用户名。 | +| `display_name` | `String` | 展示名。 | +| `phone_number_masked` | `Option` | 脱敏手机号。 | +| `phone_number_e164` | `Option` | 内部手机号索引。 | +| `login_method` | `String` | `password/phone/wechat`。 | +| `binding_status` | `String` | `active/pending_bind_phone`。 | +| `wechat_bound` | `bool` | 是否绑定微信身份。 | +| `password_hash` | `String` | 密码哈希。 | +| `password_login_enabled` | `bool` | 是否允许密码登录。 | +| `token_version` | `u64` | access token 统一失效版本。 | + +### 3.2 `auth_identity` + +当前只导入已有快照中的微信身份与手机号身份: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| `identity_id` | `String` | 主键。 | +| `user_id` | `String` | 归属账号。 | +| `provider` | `String` | `phone/wechat`。 | +| `provider_uid` | `String` | provider 主体键。 | +| `provider_union_id` | `Option` | 微信 unionid。 | +| `phone_e164` | `Option` | 手机号身份。 | +| `display_name` | `Option` | provider 显示名。 | +| `avatar_url` | `Option` | provider 头像。 | + +### 3.3 `refresh_session` + +字段对齐现有 refresh session 记录: + +| 字段 | 类型 | 说明 | +| --- | --- | --- | +| `session_id` | `String` | 主键。 | +| `user_id` | `String` | 归属账号。 | +| `refresh_token_hash` | `String` | 当前 refresh token hash。 | +| `issued_by_provider` | `String` | 创建来源。 | +| `client_info_json` | `String` | 当前客户端身份 JSON。 | +| `expires_at` | `String` | RFC3339。 | +| `revoked_at` | `Option` | RFC3339。 | +| `created_at` | `String` | RFC3339。 | +| `updated_at` | `String` | RFC3339。 | +| `last_seen_at` | `String` | RFC3339。 | + +## 4. 导入语义 + +`import_auth_store_snapshot` 固定行为: + +1. 读取 `auth_store_snapshot/default`。 +2. JSON 解析失败返回 `ok=false` 和中文错误。 +3. 导入前清空三张正式 auth 表,避免重复导入产生脏数据。 +4. 按快照内容重建账号、身份、refresh session。 +5. 返回导入计数,便于本地验证。 + +## 5. 完成定义 + +1. `spacetime-module` wasm check 通过。 +2. Rust bindings 已刷新。 +3. `spacetime-client` 暴露导入 procedure facade。 +4. `api-server/spacetime-client/module-auth` 定向检查通过。 + diff --git a/server-rs/crates/api-server/src/state.rs b/server-rs/crates/api-server/src/state.rs index 14e2e252..67dc068c 100644 --- a/server-rs/crates/api-server/src/state.rs +++ b/server-rs/crates/api-server/src/state.rs @@ -217,6 +217,8 @@ impl AppState { self.spacetime_client .upsert_auth_store_snapshot(snapshot_json, updated_at_micros) .await?; + // ????????????????????????????????? + self.spacetime_client.import_auth_store_snapshot().await?; Ok(()) } @@ -229,19 +231,38 @@ impl AppState { token: config.spacetime_token.clone(), pool_size: config.spacetime_pool_size, }); + match spacetime_client + .export_auth_store_snapshot_from_tables() + .await + { + Ok(snapshot) => { + if let Some(snapshot_json) = snapshot.snapshot_json { + if !snapshot_json.trim().is_empty() { + let auth_store = InMemoryAuthStore::from_snapshot_json(&snapshot_json) + .map_err(AppStateInitError::AuthStore)?; + info!("?? SpacetimeDB ???????????"); + return Self::new_with_auth_store(config, auth_store); + } + } + } + Err(error) => { + warn!(error = %error, "? SpacetimeDB ????????????????"); + } + } + match spacetime_client.get_auth_store_snapshot().await { Ok(snapshot) => { if let Some(snapshot_json) = snapshot.snapshot_json { if !snapshot_json.trim().is_empty() { let auth_store = InMemoryAuthStore::from_snapshot_json(&snapshot_json) .map_err(AppStateInitError::AuthStore)?; - info!("已从 SpacetimeDB 恢复认证快照"); + info!("?? SpacetimeDB ???????????"); return Self::new_with_auth_store(config, auth_store); } } } Err(error) => { - warn!(error = %error, "从 SpacetimeDB 恢复认证快照失败,回退到本地快照"); + warn!(error = %error, "? SpacetimeDB ?????????????????"); } } diff --git a/server-rs/crates/spacetime-client/src/ai.rs b/server-rs/crates/spacetime-client/src/ai.rs index 65d0de12..4c931a4a 100644 --- a/server-rs/crates/spacetime-client/src/ai.rs +++ b/server-rs/crates/spacetime-client/src/ai.rs @@ -1,11 +1,12 @@ use super::*; +use crate::mapper::*; impl SpacetimeClient { pub async fn create_ai_task( &self, input: DomainAiTaskCreateInput, ) -> Result { - let procedure_input = map_ai_task_create_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection.procedures().create_ai_task_and_return_then( @@ -21,12 +22,11 @@ impl SpacetimeClient { .await } - pub async fn start_ai_task( &self, input: DomainAiTaskStartInput, ) -> Result<(), SpacetimeClientError> { - let reducer_input = map_ai_task_start_input(input); + let reducer_input = input.into(); self.call_reducer_after_connect(move |connection, sender| { let callback_sender = sender.clone(); @@ -49,12 +49,11 @@ impl SpacetimeClient { .await } - pub async fn start_ai_task_stage( &self, input: DomainAiTaskStageStartInput, ) -> Result<(), SpacetimeClientError> { - let reducer_input = map_ai_task_stage_start_input(input); + let reducer_input = input.into(); self.call_reducer_after_connect(move |connection, sender| { let callback_sender = sender.clone(); @@ -77,12 +76,11 @@ impl SpacetimeClient { .await } - pub async fn append_ai_text_chunk( &self, input: DomainAiTextChunkAppendInput, ) -> Result { - let procedure_input = map_ai_text_chunk_append_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection @@ -97,12 +95,11 @@ impl SpacetimeClient { .await } - pub async fn complete_ai_stage( &self, input: DomainAiStageCompletionInput, ) -> Result { - let procedure_input = map_ai_stage_completion_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection.procedures().complete_ai_stage_and_return_then( @@ -118,12 +115,11 @@ impl SpacetimeClient { .await } - pub async fn attach_ai_result_reference( &self, input: DomainAiResultReferenceInput, ) -> Result { - let procedure_input = map_ai_result_reference_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection @@ -138,12 +134,11 @@ impl SpacetimeClient { .await } - pub async fn complete_ai_task( &self, input: DomainAiTaskFinishInput, ) -> Result { - let procedure_input = map_ai_task_finish_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection.procedures().complete_ai_task_and_return_then( @@ -159,12 +154,11 @@ impl SpacetimeClient { .await } - pub async fn fail_ai_task( &self, input: DomainAiTaskFailureInput, ) -> Result { - let procedure_input = map_ai_task_failure_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection.procedures().fail_ai_task_and_return_then( @@ -180,12 +174,11 @@ impl SpacetimeClient { .await } - pub async fn cancel_ai_task( &self, input: DomainAiTaskCancelInput, ) -> Result { - let procedure_input = map_ai_task_cancel_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection.procedures().cancel_ai_task_and_return_then( @@ -200,6 +193,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/assets.rs b/server-rs/crates/spacetime-client/src/assets.rs index 5f4fbe2a..cc27d9ac 100644 --- a/server-rs/crates/spacetime-client/src/assets.rs +++ b/server-rs/crates/spacetime-client/src/assets.rs @@ -5,7 +5,7 @@ impl SpacetimeClient { &self, input: module_assets::AssetObjectUpsertInput, ) -> Result { - let procedure_input = map_upsert_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection @@ -20,12 +20,11 @@ impl SpacetimeClient { .await } - pub async fn bind_asset_object_to_entity( &self, input: module_assets::AssetEntityBindingInput, ) -> Result { - let procedure_input = map_entity_binding_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection @@ -39,6 +38,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/auth.rs b/server-rs/crates/spacetime-client/src/auth.rs index 60852ffe..67f068eb 100644 --- a/server-rs/crates/spacetime-client/src/auth.rs +++ b/server-rs/crates/spacetime-client/src/auth.rs @@ -1,6 +1,22 @@ use super::*; impl SpacetimeClient { + pub async fn export_auth_store_snapshot_from_tables( + &self, + ) -> Result { + self.call_after_connect(move |connection, sender| { + connection + .procedures() + .export_auth_store_snapshot_from_tables_then(move |_, result| { + let mapped = result + .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) + .and_then(map_auth_store_snapshot_procedure_result); + send_once(&sender, mapped); + }); + }) + .await + } + pub async fn get_auth_store_snapshot( &self, ) -> Result { @@ -17,7 +33,6 @@ impl SpacetimeClient { .await } - pub async fn upsert_auth_store_snapshot( &self, snapshot_json: String, @@ -42,5 +57,19 @@ impl SpacetimeClient { .await } - + pub async fn import_auth_store_snapshot( + &self, + ) -> Result { + self.call_after_connect(move |connection, sender| { + connection + .procedures() + .import_auth_store_snapshot_then(move |_, result| { + let mapped = result + .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) + .and_then(map_auth_store_snapshot_import_procedure_result); + send_once(&sender, mapped); + }); + }) + .await + } } diff --git a/server-rs/crates/spacetime-client/src/big_fish.rs b/server-rs/crates/spacetime-client/src/big_fish.rs index 54b65a3f..1c7d2003 100644 --- a/server-rs/crates/spacetime-client/src/big_fish.rs +++ b/server-rs/crates/spacetime-client/src/big_fish.rs @@ -1,4 +1,5 @@ use super::*; +use crate::mapper::*; impl SpacetimeClient { pub async fn create_big_fish_session( @@ -28,7 +29,6 @@ impl SpacetimeClient { .await } - pub async fn get_big_fish_session( &self, session_id: String, @@ -52,7 +52,6 @@ impl SpacetimeClient { .await } - pub async fn list_big_fish_works( &self, owner_user_id: String, @@ -72,7 +71,6 @@ impl SpacetimeClient { .await } - pub async fn submit_big_fish_message( &self, input: BigFishMessageSubmitRecordInput, @@ -100,6 +98,34 @@ impl SpacetimeClient { .await } + pub async fn finalize_big_fish_agent_message( + &self, + input: BigFishMessageFinalizeRecordInput, + ) -> Result { + let procedure_input = BigFishMessageFinalizeInput { + session_id: input.session_id, + owner_user_id: input.owner_user_id, + assistant_message_id: input.assistant_message_id, + assistant_reply_text: input.assistant_reply_text, + stage: parse_big_fish_creation_stage(&input.stage)?, + progress_percent: input.progress_percent, + anchor_pack_json: input.anchor_pack_json, + error_message: input.error_message, + updated_at_micros: input.updated_at_micros, + }; + + self.call_after_connect(move |connection, sender| { + connection + .procedures() + .finalize_big_fish_agent_message_turn_then(procedure_input, move |_, result| { + let mapped = result + .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) + .and_then(map_big_fish_session_procedure_result); + send_once(&sender, mapped); + }); + }) + .await + } pub async fn compile_big_fish_draft( &self, @@ -127,7 +153,6 @@ impl SpacetimeClient { .await } - pub async fn generate_big_fish_asset( &self, input: BigFishAssetGenerateRecordInput, @@ -135,7 +160,7 @@ impl SpacetimeClient { let procedure_input = BigFishAssetGenerateInput { session_id: input.session_id, owner_user_id: input.owner_user_id, - asset_kind: map_big_fish_asset_kind_input(input.asset_kind.as_str())?, + asset_kind: input.asset_kind.as_str().try_into()?, level: input.level, motion_key: input.motion_key, asset_url: input.asset_url, @@ -156,7 +181,6 @@ impl SpacetimeClient { .await } - pub async fn publish_big_fish_game( &self, session_id: String, @@ -183,7 +207,6 @@ impl SpacetimeClient { .await } - pub async fn start_big_fish_run( &self, input: BigFishRunStartRecordInput, @@ -208,7 +231,6 @@ impl SpacetimeClient { .await } - pub async fn submit_big_fish_input( &self, input: BigFishRunInputSubmitRecordInput, @@ -235,7 +257,6 @@ impl SpacetimeClient { .await } - pub async fn get_big_fish_run( &self, run_id: String, @@ -258,6 +279,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/combat.rs b/server-rs/crates/spacetime-client/src/combat.rs index 9d087537..c683de08 100644 --- a/server-rs/crates/spacetime-client/src/combat.rs +++ b/server-rs/crates/spacetime-client/src/combat.rs @@ -1,4 +1,5 @@ use super::*; +use crate::mapper::*; impl SpacetimeClient { pub async fn create_battle_state( @@ -7,7 +8,7 @@ impl SpacetimeClient { ) -> Result { validate_battle_state_input(&input) .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?; - let procedure_input = map_battle_state_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection.procedures().create_battle_state_and_return_then( @@ -23,15 +24,13 @@ impl SpacetimeClient { .await } - pub async fn get_battle_state( &self, battle_state_id: String, ) -> Result { - let procedure_input = map_battle_state_query_input( - build_battle_state_query_input(battle_state_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_battle_state_query_input(battle_state_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection @@ -46,14 +45,13 @@ impl SpacetimeClient { .await } - pub async fn resolve_combat_action( &self, input: DomainResolveCombatActionInput, ) -> Result { validate_resolve_combat_action_input(&input) .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?; - let procedure_input = map_resolve_combat_action_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection @@ -67,6 +65,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/custom_world.rs b/server-rs/crates/spacetime-client/src/custom_world.rs index f4883244..3f651ed5 100644 --- a/server-rs/crates/spacetime-client/src/custom_world.rs +++ b/server-rs/crates/spacetime-client/src/custom_world.rs @@ -1,4 +1,5 @@ use super::*; +use crate::mapper::*; impl SpacetimeClient { pub async fn list_custom_world_profiles( @@ -21,7 +22,6 @@ impl SpacetimeClient { .await } - pub async fn get_custom_world_library_detail( &self, owner_user_id: String, @@ -45,12 +45,11 @@ impl SpacetimeClient { .await } - pub async fn upsert_custom_world_profile( &self, input: CustomWorldProfileUpsertRecordInput, ) -> Result { - let procedure_input = map_custom_world_profile_upsert_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection @@ -65,7 +64,6 @@ impl SpacetimeClient { .await } - pub async fn publish_custom_world_profile( &self, profile_id: String, @@ -97,7 +95,6 @@ impl SpacetimeClient { .await } - pub async fn unpublish_custom_world_profile( &self, profile_id: String, @@ -128,7 +125,6 @@ impl SpacetimeClient { .await } - pub async fn delete_custom_world_profile( &self, profile_id: String, @@ -154,7 +150,6 @@ impl SpacetimeClient { .await } - pub async fn list_custom_world_gallery_entries( &self, ) -> Result, SpacetimeClientError> { @@ -171,7 +166,6 @@ impl SpacetimeClient { .await } - pub async fn get_custom_world_gallery_detail( &self, owner_user_id: String, @@ -195,7 +189,6 @@ impl SpacetimeClient { .await } - pub async fn get_custom_world_gallery_detail_by_code( &self, public_work_code: String, @@ -215,12 +208,11 @@ impl SpacetimeClient { .await } - pub async fn publish_custom_world_world( &self, input: CustomWorldPublishWorldRecordInput, ) -> Result { - let procedure_input = map_custom_world_publish_world_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection.procedures().publish_custom_world_world_then( @@ -236,7 +228,6 @@ impl SpacetimeClient { .await } - pub async fn create_custom_world_agent_session( &self, input: CustomWorldAgentSessionCreateRecordInput, @@ -275,7 +266,6 @@ impl SpacetimeClient { .await } - pub async fn get_custom_world_agent_session( &self, session_id: String, @@ -300,7 +290,6 @@ impl SpacetimeClient { .await } - pub async fn list_custom_world_works( &self, owner_user_id: String, @@ -321,7 +310,6 @@ impl SpacetimeClient { .await } - pub async fn get_custom_world_agent_card_detail( &self, session_id: String, @@ -347,7 +335,6 @@ impl SpacetimeClient { .await } - pub async fn execute_custom_world_agent_action( &self, input: CustomWorldAgentActionExecuteRecordInput, @@ -374,7 +361,6 @@ impl SpacetimeClient { .await } - pub async fn submit_custom_world_agent_message( &self, input: CustomWorldAgentMessageSubmitRecordInput, @@ -401,7 +387,6 @@ impl SpacetimeClient { .await } - pub async fn finalize_custom_world_agent_message( &self, input: CustomWorldAgentMessageFinalizeRecordInput, @@ -451,7 +436,6 @@ impl SpacetimeClient { .await } - pub async fn get_custom_world_agent_operation( &self, session_id: String, @@ -476,6 +460,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/inventory.rs b/server-rs/crates/spacetime-client/src/inventory.rs index 06dfd71b..c3e66ef2 100644 --- a/server-rs/crates/spacetime-client/src/inventory.rs +++ b/server-rs/crates/spacetime-client/src/inventory.rs @@ -6,10 +6,10 @@ impl SpacetimeClient { runtime_session_id: String, actor_user_id: String, ) -> Result { - let procedure_input = map_runtime_inventory_state_query_input( + let procedure_input = build_runtime_inventory_state_query_input(runtime_session_id, actor_user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().get_runtime_inventory_state_then( @@ -24,6 +24,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/lib.rs b/server-rs/crates/spacetime-client/src/lib.rs index 63f2b08b..f8451a57 100644 --- a/server-rs/crates/spacetime-client/src/lib.rs +++ b/server-rs/crates/spacetime-client/src/lib.rs @@ -3,7 +3,8 @@ pub mod module_bindings; mod mapper; -pub use mapper::*; +pub(crate) use mapper::*; +pub use mapper::{BattleStateRecord, ResolveCombatActionRecord, CustomWorldLibraryEntryRecord, CustomWorldGalleryEntryRecord, CustomWorldLibraryMutationRecord, CustomWorldPublishedProfileCompileRecord, CustomWorldPublishWorldRecord, CustomWorldAgentMessageRecord, CustomWorldAgentOperationRecord, CustomWorldDraftCardRecord, CustomWorldSupportedActionRecord, CustomWorldCheckpointRecord, CustomWorldAgentCheckpointRecord, CustomWorldResultPreviewBlockerRecord, CustomWorldPublishGateRecord, CustomWorldWorkSummaryRecord, CustomWorldDraftCardDetailSectionRecord, CustomWorldDraftCardDetailRecord, CustomWorldAgentSessionRecord, CustomWorldProfileUpsertRecordInput, CustomWorldPublishWorldRecordInput, CustomWorldAgentSessionCreateRecordInput, CustomWorldAgentMessageSubmitRecordInput, CustomWorldAgentMessageFinalizeRecordInput, CustomWorldAgentActionExecuteRecordInput, CustomWorldAgentActionExecuteRecord, PuzzleAgentSessionCreateRecordInput, PuzzleAgentMessageSubmitRecordInput, PuzzleAgentMessageFinalizeRecordInput, PuzzleGeneratedImagesSaveRecordInput, PuzzleSelectCoverImageRecordInput, PuzzlePublishRecordInput, PuzzleWorkUpsertRecordInput, PuzzleRunStartRecordInput, PuzzleRunSwapRecordInput, PuzzleRunDragRecordInput, PuzzleRunNextLevelRecordInput, PuzzleAnchorItemRecord, PuzzleAnchorPackRecord, PuzzleCreatorIntentRecord, PuzzleGeneratedImageCandidateRecord, PuzzleResultDraftRecord, PuzzleAgentMessageRecord, PuzzleAgentSuggestedActionRecord, PuzzleResultPreviewBlockerRecord, PuzzleResultPreviewFindingRecord, PuzzleResultPreviewRecord, PuzzleAgentSessionRecord, PuzzleWorkProfileRecord, PuzzleCellPositionRecord, PuzzlePieceStateRecord, PuzzleMergedGroupRecord, PuzzleBoardRecord, PuzzleRuntimeLevelRecord, PuzzleRunRecord, BigFishSessionCreateRecordInput, BigFishMessageSubmitRecordInput, BigFishMessageFinalizeRecordInput, BigFishAssetGenerateRecordInput, BigFishRunStartRecordInput, BigFishRunInputSubmitRecordInput, BigFishAnchorItemRecord, BigFishAnchorPackRecord, BigFishLevelBlueprintRecord, BigFishBackgroundBlueprintRecord, BigFishRuntimeParamsRecord, BigFishGameDraftRecord, BigFishAgentMessageRecord, BigFishAssetSlotRecord, BigFishAssetCoverageRecord, BigFishSessionRecord, BigFishWorkSummaryRecord, BigFishVector2Record, BigFishRuntimeEntityRecord, BigFishRuntimeRecord, ResolveNpcBattleInteractionInput, AiTaskStageRecord, AiResultReferenceRecord, AiTextChunkRecord, AiTaskRecord, AiTaskMutationRecord, NpcStateRecord, NpcInteractionRecord, NpcBattleInteractionRecord}; pub mod ai; pub mod assets; @@ -84,17 +85,15 @@ use module_puzzle::{ PuzzleWorkProfile as DomainPuzzleWorkProfile, }; use module_runtime::{ - RuntimeBrowseHistoryRecord, RuntimeBrowseHistoryThemeMode as DomainRuntimeBrowseHistoryThemeMode, - RuntimePlatformTheme as DomainRuntimePlatformTheme, + RuntimeBrowseHistoryRecord, RuntimePlatformTheme as DomainRuntimePlatformTheme, RuntimeProfileDashboardRecord, RuntimeProfilePlayStatsRecord, RuntimeProfileSaveArchiveRecord, - RuntimeProfileWalletLedgerEntryRecord, - RuntimeProfileWalletLedgerSourceType as DomainRuntimeProfileWalletLedgerSourceType, - RuntimeSettingsRecord, RuntimeSnapshotRecord, build_runtime_browse_history_clear_input, - build_runtime_browse_history_list_input, build_runtime_browse_history_record, - build_runtime_browse_history_sync_input, build_runtime_profile_dashboard_get_input, - build_runtime_profile_dashboard_record, build_runtime_profile_play_stats_get_input, - build_runtime_profile_play_stats_record, build_runtime_profile_save_archive_list_input, - build_runtime_profile_save_archive_record, build_runtime_profile_save_archive_resume_input, + RuntimeProfileWalletLedgerEntryRecord, RuntimeSettingsRecord, RuntimeSnapshotRecord, + build_runtime_browse_history_clear_input, build_runtime_browse_history_list_input, + build_runtime_browse_history_record, build_runtime_browse_history_sync_input, + build_runtime_profile_dashboard_get_input, build_runtime_profile_dashboard_record, + build_runtime_profile_play_stats_get_input, build_runtime_profile_play_stats_record, + build_runtime_profile_save_archive_list_input, build_runtime_profile_save_archive_record, + build_runtime_profile_save_archive_resume_input, build_runtime_profile_wallet_ledger_entry_record, build_runtime_profile_wallet_ledger_list_input, build_runtime_setting_get_input, build_runtime_setting_record, build_runtime_setting_upsert_input, @@ -121,266 +120,7 @@ use tokio::{ time::timeout, }; -<<<<<<< HEAD -use crate::module_bindings::{ - AiResultReferenceInput as BindingAiResultReferenceInput, - AiResultReferenceKind as BindingAiResultReferenceKind, - AiResultReferenceSnapshot as BindingAiResultReferenceSnapshot, - AiStageCompletionInput as BindingAiStageCompletionInput, - AiTaskCancelInput as BindingAiTaskCancelInput, AiTaskCreateInput as BindingAiTaskCreateInput, - AiTaskFailureInput as BindingAiTaskFailureInput, AiTaskFinishInput as BindingAiTaskFinishInput, - AiTaskKind as BindingAiTaskKind, AiTaskProcedureResult as BindingAiTaskProcedureResult, - AiTaskSnapshot as BindingAiTaskSnapshot, AiTaskStageBlueprint as BindingAiTaskStageBlueprint, - AiTaskStageKind as BindingAiTaskStageKind, AiTaskStageSnapshot as BindingAiTaskStageSnapshot, - AiTaskStageStartInput as BindingAiTaskStageStartInput, - AiTaskStageStatus as BindingAiTaskStageStatus, AiTaskStartInput as BindingAiTaskStartInput, - AiTaskStatus as BindingAiTaskStatus, AiTextChunkAppendInput as BindingAiTextChunkAppendInput, - AiTextChunkSnapshot as BindingAiTextChunkSnapshot, - AssetEntityBindingInput as BindingAssetEntityBindingInput, - AssetEntityBindingProcedureResult as BindingAssetEntityBindingProcedureResult, - AssetEntityBindingSnapshot as BindingAssetEntityBindingSnapshot, - AssetObjectProcedureResult as BindingAssetObjectProcedureResult, - AssetObjectUpsertInput as BindingAssetObjectUpsertInput, - AssetObjectUpsertSnapshot as BindingAssetObjectUpsertSnapshot, BattleMode as BindingBattleMode, - BattleStateInput as BindingBattleStateInput, - BattleStateProcedureResult as BindingBattleStateProcedureResult, - BattleStateQueryInput as BindingBattleStateQueryInput, - BattleStateSnapshot as BindingBattleStateSnapshot, BattleStatus as BindingBattleStatus, - BigFishAgentMessageKind as BindingBigFishAgentMessageKind, - BigFishAgentMessageRole as BindingBigFishAgentMessageRole, - BigFishAgentMessageSnapshot as BindingBigFishAgentMessageSnapshot, - BigFishAnchorItem as BindingBigFishAnchorItem, BigFishAnchorPack as BindingBigFishAnchorPack, - BigFishAnchorStatus as BindingBigFishAnchorStatus, - BigFishAssetCoverage as BindingBigFishAssetCoverage, - BigFishAssetGenerateInput as BindingBigFishAssetGenerateInput, - BigFishAssetKind as BindingBigFishAssetKind, - BigFishAssetSlotSnapshot as BindingBigFishAssetSlotSnapshot, - BigFishAssetStatus as BindingBigFishAssetStatus, - BigFishBackgroundBlueprint as BindingBigFishBackgroundBlueprint, - BigFishCreationStage as BindingBigFishCreationStage, - BigFishDraftCompileInput as BindingBigFishDraftCompileInput, - BigFishGameDraft as BindingBigFishGameDraft, - BigFishLevelBlueprint as BindingBigFishLevelBlueprint, - BigFishMessageFinalizeInput as BindingBigFishMessageFinalizeInput, - BigFishMessageSubmitInput as BindingBigFishMessageSubmitInput, - BigFishPublishInput as BindingBigFishPublishInput, - BigFishRunGetInput as BindingBigFishRunGetInput, - BigFishRunInputSubmitInput as BindingBigFishRunInputSubmitInput, - BigFishRunProcedureResult as BindingBigFishRunProcedureResult, - BigFishRunStartInput as BindingBigFishRunStartInput, - BigFishRunStatus as BindingBigFishRunStatus, - BigFishRuntimeEntity as BindingBigFishRuntimeEntity, - BigFishRuntimeParams as BindingBigFishRuntimeParams, - BigFishRuntimeSnapshot as BindingBigFishRuntimeSnapshot, - BigFishSessionCreateInput as BindingBigFishSessionCreateInput, - BigFishSessionGetInput as BindingBigFishSessionGetInput, - BigFishSessionProcedureResult as BindingBigFishSessionProcedureResult, - BigFishSessionSnapshot as BindingBigFishSessionSnapshot, - BigFishVector2 as BindingBigFishVector2, BigFishWorksListInput as BindingBigFishWorksListInput, - BigFishWorksProcedureResult as BindingBigFishWorksProcedureResult, - CombatOutcome as BindingCombatOutcome, - CustomWorldAgentActionExecuteInput as BindingCustomWorldAgentActionExecuteInput, - CustomWorldAgentActionExecuteResult as BindingCustomWorldAgentActionExecuteResult, - CustomWorldAgentCardDetailGetInput as BindingCustomWorldAgentCardDetailGetInput, - CustomWorldAgentMessageFinalizeInput as BindingCustomWorldAgentMessageFinalizeInput, - CustomWorldAgentMessageSnapshot as BindingCustomWorldAgentMessageSnapshot, - CustomWorldAgentMessageSubmitInput as BindingCustomWorldAgentMessageSubmitInput, - CustomWorldAgentOperationGetInput as BindingCustomWorldAgentOperationGetInput, - CustomWorldAgentOperationProcedureResult as BindingCustomWorldAgentOperationProcedureResult, - CustomWorldAgentOperationSnapshot as BindingCustomWorldAgentOperationSnapshot, - CustomWorldAgentSessionCreateInput as BindingCustomWorldAgentSessionCreateInput, - CustomWorldAgentSessionGetInput as BindingCustomWorldAgentSessionGetInput, - CustomWorldAgentSessionProcedureResult as BindingCustomWorldAgentSessionProcedureResult, - CustomWorldAgentSessionSnapshot as BindingCustomWorldAgentSessionSnapshot, - CustomWorldDraftCardDetailResult as BindingCustomWorldDraftCardDetailResult, - CustomWorldDraftCardDetailSectionSnapshot as BindingCustomWorldDraftCardDetailSectionSnapshot, - CustomWorldDraftCardDetailSnapshot as BindingCustomWorldDraftCardDetailSnapshot, - CustomWorldDraftCardSnapshot as BindingCustomWorldDraftCardSnapshot, - CustomWorldGalleryDetailByCodeInput as BindingCustomWorldGalleryDetailByCodeInput, - CustomWorldGalleryDetailInput as BindingCustomWorldGalleryDetailInput, - CustomWorldGalleryEntrySnapshot as BindingCustomWorldGalleryEntrySnapshot, - CustomWorldGalleryListResult as BindingCustomWorldGalleryListResult, - CustomWorldLibraryDetailInput as BindingCustomWorldLibraryDetailInput, - CustomWorldLibraryMutationResult as BindingCustomWorldLibraryMutationResult, - CustomWorldProfileDeleteInput as BindingCustomWorldProfileDeleteInput, - CustomWorldProfileListInput as BindingCustomWorldProfileListInput, - CustomWorldProfileListResult as BindingCustomWorldProfileListResult, - CustomWorldProfilePublishInput as BindingCustomWorldProfilePublishInput, - CustomWorldProfileSnapshot as BindingCustomWorldProfileSnapshot, - CustomWorldProfileUnpublishInput as BindingCustomWorldProfileUnpublishInput, - CustomWorldProfileUpsertInput as BindingCustomWorldProfileUpsertInput, - CustomWorldPublicationStatus as BindingCustomWorldPublicationStatus, - CustomWorldPublishWorldInput as BindingCustomWorldPublishWorldInput, - CustomWorldPublishWorldResult as BindingCustomWorldPublishWorldResult, - CustomWorldPublishedProfileCompileSnapshot as BindingCustomWorldPublishedProfileCompileSnapshot, - CustomWorldThemeMode as BindingCustomWorldThemeMode, - CustomWorldWorkSummarySnapshot as BindingCustomWorldWorkSummarySnapshot, - CustomWorldWorksListInput as BindingCustomWorldWorksListInput, - CustomWorldWorksListResult as BindingCustomWorldWorksListResult, DbConnection, - InventoryContainerKind as BindingInventoryContainerKind, - InventoryEquipmentSlot as BindingInventoryEquipmentSlot, - InventoryItemRarity as BindingInventoryItemRarity, - InventoryItemSourceKind as BindingInventoryItemSourceKind, - InventorySlotSnapshot as BindingInventorySlotSnapshot, - NpcBattleInteractionProcedureResult as BindingNpcBattleInteractionProcedureResult, - NpcBattleInteractionResult as BindingNpcBattleInteractionResult, - NpcInteractionBattleMode as BindingNpcInteractionBattleMode, - NpcInteractionResult as BindingNpcInteractionResult, - NpcInteractionStatus as BindingNpcInteractionStatus, - NpcRelationStance as BindingNpcRelationStance, NpcRelationState as BindingNpcRelationState, - NpcStanceProfile as BindingNpcStanceProfile, NpcStateSnapshot as BindingNpcStateSnapshot, - PuzzleAgentMessageFinalizeInput as BindingPuzzleAgentMessageFinalizeInput, - PuzzleAgentMessageSubmitInput as BindingPuzzleAgentMessageSubmitInput, - PuzzleAgentSessionCreateInput as BindingPuzzleAgentSessionCreateInput, - PuzzleAgentSessionGetInput as BindingPuzzleAgentSessionGetInput, - PuzzleAgentSessionProcedureResult as BindingPuzzleAgentSessionProcedureResult, - PuzzleDraftCompileInput as BindingPuzzleDraftCompileInput, - PuzzleGeneratedImagesSaveInput as BindingPuzzleGeneratedImagesSaveInput, - PuzzlePublishInput as BindingPuzzlePublishInput, - PuzzleRunDragInput as BindingPuzzleRunDragInput, PuzzleRunGetInput as BindingPuzzleRunGetInput, - PuzzleRunNextLevelInput as BindingPuzzleRunNextLevelInput, - PuzzleRunProcedureResult as BindingPuzzleRunProcedureResult, - PuzzleRunStartInput as BindingPuzzleRunStartInput, - PuzzleRunSwapInput as BindingPuzzleRunSwapInput, - PuzzleSelectCoverImageInput as BindingPuzzleSelectCoverImageInput, - PuzzleWorkGetInput as BindingPuzzleWorkGetInput, - PuzzleWorkProcedureResult as BindingPuzzleWorkProcedureResult, - PuzzleWorkUpsertInput as BindingPuzzleWorkUpsertInput, - PuzzleWorksListInput as BindingPuzzleWorksListInput, - PuzzleWorksProcedureResult as BindingPuzzleWorksProcedureResult, - ResolveCombatActionInput as BindingResolveCombatActionInput, - ResolveCombatActionProcedureResult as BindingResolveCombatActionProcedureResult, - ResolveCombatActionResult as BindingResolveCombatActionResult, - ResolveNpcBattleInteractionInput as BindingResolveNpcBattleInteractionInput, - ResolveNpcInteractionInput as BindingResolveNpcInteractionInput, - RuntimeBrowseHistoryClearInput as BindingRuntimeBrowseHistoryClearInput, - RuntimeBrowseHistoryListInput as BindingRuntimeBrowseHistoryListInput, - RuntimeBrowseHistoryProcedureResult as BindingRuntimeBrowseHistoryProcedureResult, - RuntimeBrowseHistorySnapshot as BindingRuntimeBrowseHistorySnapshot, - RuntimeBrowseHistorySyncInput as BindingRuntimeBrowseHistorySyncInput, - RuntimeBrowseHistoryThemeMode as BindingRuntimeBrowseHistoryThemeMode, - RuntimeBrowseHistoryWriteInput as BindingRuntimeBrowseHistoryWriteInput, - RuntimeInventoryStateProcedureResult as BindingRuntimeInventoryStateProcedureResult, - RuntimeInventoryStateQueryInput as BindingRuntimeInventoryStateQueryInput, - RuntimeInventoryStateSnapshot as BindingRuntimeInventoryStateSnapshot, - RuntimeItemEquipmentSlot as BindingRuntimeItemEquipmentSlot, - RuntimeItemRewardItemRarity as BindingRuntimeItemRewardItemRarity, - RuntimeItemRewardItemSnapshot as BindingRuntimeItemRewardItemSnapshot, - RuntimePlatformTheme as BindingRuntimePlatformTheme, - RuntimeProfileDashboardGetInput as BindingRuntimeProfileDashboardGetInput, - RuntimeProfileDashboardProcedureResult as BindingRuntimeProfileDashboardProcedureResult, - RuntimeProfileDashboardSnapshot as BindingRuntimeProfileDashboardSnapshot, - RuntimeProfilePlayStatsGetInput as BindingRuntimeProfilePlayStatsGetInput, - RuntimeProfilePlayStatsProcedureResult as BindingRuntimeProfilePlayStatsProcedureResult, - RuntimeProfilePlayStatsSnapshot as BindingRuntimeProfilePlayStatsSnapshot, - RuntimeProfilePlayedWorldSnapshot as BindingRuntimeProfilePlayedWorldSnapshot, - RuntimeProfileSaveArchiveListInput as BindingRuntimeProfileSaveArchiveListInput, - RuntimeProfileSaveArchiveProcedureResult as BindingRuntimeProfileSaveArchiveProcedureResult, - RuntimeProfileSaveArchiveResumeInput as BindingRuntimeProfileSaveArchiveResumeInput, - RuntimeProfileSaveArchiveSnapshot as BindingRuntimeProfileSaveArchiveSnapshot, - RuntimeProfileWalletLedgerEntrySnapshot as BindingRuntimeProfileWalletLedgerEntrySnapshot, - RuntimeProfileWalletLedgerListInput as BindingRuntimeProfileWalletLedgerListInput, - RuntimeProfileWalletLedgerProcedureResult as BindingRuntimeProfileWalletLedgerProcedureResult, - RuntimeProfileWalletLedgerSourceType as BindingRuntimeProfileWalletLedgerSourceType, - RuntimeSettingGetInput as BindingRuntimeSettingGetInput, - RuntimeSettingProcedureResult as BindingRuntimeSettingProcedureResult, - RuntimeSettingSnapshot as BindingRuntimeSettingSnapshot, - RuntimeSettingUpsertInput as BindingRuntimeSettingUpsertInput, - RuntimeSnapshot as BindingRuntimeSnapshot, - RuntimeSnapshotDeleteInput as BindingRuntimeSnapshotDeleteInput, - RuntimeSnapshotGetInput as BindingRuntimeSnapshotGetInput, - RuntimeSnapshotProcedureResult as BindingRuntimeSnapshotProcedureResult, - RuntimeSnapshotUpsertInput as BindingRuntimeSnapshotUpsertInput, - StoryContinueInput as BindingStoryContinueInput, StoryEventKind as BindingStoryEventKind, - StoryEventSnapshot as BindingStoryEventSnapshot, StorySessionInput as BindingStorySessionInput, - StorySessionProcedureResult as BindingStorySessionProcedureResult, - StorySessionSnapshot as BindingStorySessionSnapshot, - StorySessionStateInput as BindingStorySessionStateInput, - StorySessionStateProcedureResult as BindingStorySessionStateProcedureResult, - StorySessionStatus as BindingStorySessionStatus, - advance_puzzle_next_level_procedure::advance_puzzle_next_level as _, - append_ai_text_chunk_and_return_procedure::append_ai_text_chunk_and_return as _, - attach_ai_result_reference_and_return_procedure::attach_ai_result_reference_and_return as _, - begin_story_session_and_return_procedure::begin_story_session_and_return as _, - bind_asset_object_to_entity_and_return_procedure::bind_asset_object_to_entity_and_return as _, - cancel_ai_task_and_return_procedure::cancel_ai_task_and_return as _, - clear_platform_browse_history_and_return_procedure::clear_platform_browse_history_and_return as _, - compile_big_fish_draft_procedure::compile_big_fish_draft as _, - compile_puzzle_agent_draft_procedure::compile_puzzle_agent_draft as _, - complete_ai_stage_and_return_procedure::complete_ai_stage_and_return as _, - complete_ai_task_and_return_procedure::complete_ai_task_and_return as _, - confirm_asset_object_and_return_procedure::confirm_asset_object_and_return as _, - continue_story_and_return_procedure::continue_story_and_return as _, - create_ai_task_and_return_procedure::create_ai_task_and_return as _, - create_battle_state_and_return_procedure::create_battle_state_and_return as _, - create_big_fish_session_procedure::create_big_fish_session as _, - create_custom_world_agent_session_procedure::create_custom_world_agent_session as _, - create_puzzle_agent_session_procedure::create_puzzle_agent_session as _, - delete_custom_world_profile_and_return_procedure::delete_custom_world_profile_and_return as _, - delete_runtime_snapshot_and_return_procedure::delete_runtime_snapshot_and_return as _, - drag_puzzle_piece_or_group_procedure::drag_puzzle_piece_or_group as _, - execute_custom_world_agent_action_procedure::execute_custom_world_agent_action as _, - fail_ai_task_and_return_procedure::fail_ai_task_and_return as _, - finalize_big_fish_agent_message_turn_procedure::finalize_big_fish_agent_message_turn as _, - finalize_custom_world_agent_message_turn_procedure::finalize_custom_world_agent_message_turn as _, - finalize_puzzle_agent_message_turn_procedure::finalize_puzzle_agent_message_turn as _, - generate_big_fish_asset_procedure::generate_big_fish_asset as _, - get_battle_state_procedure::get_battle_state as _, - get_big_fish_run_procedure::get_big_fish_run as _, - get_big_fish_session_procedure::get_big_fish_session as _, - get_custom_world_agent_card_detail_procedure::get_custom_world_agent_card_detail as _, - get_custom_world_agent_operation_procedure::get_custom_world_agent_operation as _, - get_custom_world_agent_session_procedure::get_custom_world_agent_session as _, - get_custom_world_gallery_detail_by_code_procedure::get_custom_world_gallery_detail_by_code as _, - get_custom_world_gallery_detail_procedure::get_custom_world_gallery_detail as _, - get_custom_world_library_detail_procedure::get_custom_world_library_detail as _, - get_profile_dashboard_procedure::get_profile_dashboard as _, - get_profile_play_stats_procedure::get_profile_play_stats as _, - get_puzzle_agent_session_procedure::get_puzzle_agent_session as _, - get_puzzle_gallery_detail_procedure::get_puzzle_gallery_detail as _, - get_puzzle_run_procedure::get_puzzle_run as _, - get_puzzle_work_detail_procedure::get_puzzle_work_detail as _, - get_runtime_inventory_state_procedure::get_runtime_inventory_state as _, - get_runtime_setting_or_default_procedure::get_runtime_setting_or_default as _, - get_runtime_snapshot_procedure::get_runtime_snapshot as _, - get_story_session_state_procedure::get_story_session_state as _, - list_big_fish_works_procedure::list_big_fish_works as _, - list_custom_world_gallery_entries_procedure::list_custom_world_gallery_entries as _, - list_custom_world_profiles_procedure::list_custom_world_profiles as _, - list_custom_world_works_procedure::list_custom_world_works as _, - list_platform_browse_history_procedure::list_platform_browse_history as _, - list_profile_save_archives_procedure::list_profile_save_archives as _, - list_profile_wallet_ledger_procedure::list_profile_wallet_ledger as _, - list_puzzle_gallery_procedure::list_puzzle_gallery as _, - list_puzzle_works_procedure::list_puzzle_works as _, - publish_big_fish_game_procedure::publish_big_fish_game as _, - publish_custom_world_profile_and_return_procedure::publish_custom_world_profile_and_return as _, - publish_custom_world_world_procedure::publish_custom_world_world as _, - publish_puzzle_work_procedure::publish_puzzle_work as _, - resolve_combat_action_and_return_procedure::resolve_combat_action_and_return as _, - resolve_npc_battle_interaction_and_return_procedure::resolve_npc_battle_interaction_and_return as _, - resume_profile_save_archive_and_return_procedure::resume_profile_save_archive_and_return as _, - save_puzzle_generated_images_procedure::save_puzzle_generated_images as _, - select_puzzle_cover_image_procedure::select_puzzle_cover_image as _, - start_ai_task_reducer::start_ai_task as _, - start_ai_task_stage_reducer::start_ai_task_stage as _, - start_big_fish_run_procedure::start_big_fish_run as _, - start_puzzle_run_procedure::start_puzzle_run as _, - submit_big_fish_input_procedure::submit_big_fish_input as _, - submit_big_fish_message_procedure::submit_big_fish_message as _, - submit_custom_world_agent_message_procedure::submit_custom_world_agent_message as _, - submit_puzzle_agent_message_procedure::submit_puzzle_agent_message as _, - swap_puzzle_pieces_procedure::swap_puzzle_pieces as _, - unpublish_custom_world_profile_and_return_procedure::unpublish_custom_world_profile_and_return as _, - update_puzzle_work_procedure::update_puzzle_work as _, - upsert_custom_world_profile_and_return_procedure::upsert_custom_world_profile_and_return as _, - upsert_platform_browse_history_and_return_procedure::upsert_platform_browse_history_and_return as _, - upsert_runtime_setting_and_return_procedure::upsert_runtime_setting_and_return as _, - upsert_runtime_snapshot_and_return_procedure::upsert_runtime_snapshot_and_return as _, -}; -======= use crate::module_bindings::*; ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) #[derive(Clone, Debug)] pub struct SpacetimeClientConfig { @@ -396,6 +136,13 @@ pub struct AuthStoreSnapshotRecord { pub updated_at_micros: Option, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct AuthStoreSnapshotImportRecord { + pub imported_user_count: u32, + pub imported_identity_count: u32, + pub imported_refresh_session_count: u32, +} + #[derive(Clone)] pub struct SpacetimeClient { config: SpacetimeClientConfig, @@ -458,1940 +205,6 @@ impl SpacetimeClient { Self { config, pool } } -<<<<<<< HEAD - pub async fn create_ai_task( - &self, - input: DomainAiTaskCreateInput, - ) -> Result { - let procedure_input = map_ai_task_create_input(input); - - self.call_after_connect(move |connection, sender| { - connection.procedures().create_ai_task_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_ai_task_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn start_ai_task( - &self, - input: DomainAiTaskStartInput, - ) -> Result<(), SpacetimeClientError> { - let reducer_input = map_ai_task_start_input(input); - - self.call_reducer_after_connect(move |connection, sender| { - let callback_sender = sender.clone(); - if let Err(error) = - connection - .reducers - .start_ai_task_then(reducer_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(|inner| inner.map_err(SpacetimeClientError::Runtime)); - send_reducer_once(&callback_sender, mapped); - }) - { - send_reducer_once( - &sender, - Err(SpacetimeClientError::Procedure(error.to_string())), - ); - } - }) - .await - } - - pub async fn start_ai_task_stage( - &self, - input: DomainAiTaskStageStartInput, - ) -> Result<(), SpacetimeClientError> { - let reducer_input = map_ai_task_stage_start_input(input); - - self.call_reducer_after_connect(move |connection, sender| { - let callback_sender = sender.clone(); - if let Err(error) = - connection - .reducers - .start_ai_task_stage_then(reducer_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(|inner| inner.map_err(SpacetimeClientError::Runtime)); - send_reducer_once(&callback_sender, mapped); - }) - { - send_reducer_once( - &sender, - Err(SpacetimeClientError::Procedure(error.to_string())), - ); - } - }) - .await - } - - pub async fn append_ai_text_chunk( - &self, - input: DomainAiTextChunkAppendInput, - ) -> Result { - let procedure_input = map_ai_text_chunk_append_input(input); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .append_ai_text_chunk_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_ai_task_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn complete_ai_stage( - &self, - input: DomainAiStageCompletionInput, - ) -> Result { - let procedure_input = map_ai_stage_completion_input(input); - - self.call_after_connect(move |connection, sender| { - connection.procedures().complete_ai_stage_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_ai_task_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn attach_ai_result_reference( - &self, - input: DomainAiResultReferenceInput, - ) -> Result { - let procedure_input = map_ai_result_reference_input(input); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .attach_ai_result_reference_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_ai_task_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn complete_ai_task( - &self, - input: DomainAiTaskFinishInput, - ) -> Result { - let procedure_input = map_ai_task_finish_input(input); - - self.call_after_connect(move |connection, sender| { - connection.procedures().complete_ai_task_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_ai_task_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn fail_ai_task( - &self, - input: DomainAiTaskFailureInput, - ) -> Result { - let procedure_input = map_ai_task_failure_input(input); - - self.call_after_connect(move |connection, sender| { - connection.procedures().fail_ai_task_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_ai_task_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn cancel_ai_task( - &self, - input: DomainAiTaskCancelInput, - ) -> Result { - let procedure_input = map_ai_task_cancel_input(input); - - self.call_after_connect(move |connection, sender| { - connection.procedures().cancel_ai_task_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_ai_task_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn confirm_asset_object( - &self, - input: module_assets::AssetObjectUpsertInput, - ) -> Result { - let procedure_input = map_upsert_input(input); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .confirm_asset_object_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn bind_asset_object_to_entity( - &self, - input: module_assets::AssetEntityBindingInput, - ) -> Result { - let procedure_input = map_entity_binding_input(input); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .bind_asset_object_to_entity_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_entity_binding_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn get_runtime_settings( - &self, - user_id: String, - ) -> Result { - let procedure_input = map_runtime_setting_get_input( - build_runtime_setting_get_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_runtime_setting_or_default_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_setting_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn list_custom_world_profiles( - &self, - owner_user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = BindingCustomWorldProfileListInput { owner_user_id }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().list_custom_world_profiles_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_profile_list_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_custom_world_library_detail( - &self, - owner_user_id: String, - profile_id: String, - ) -> Result { - let procedure_input = BindingCustomWorldLibraryDetailInput { - owner_user_id, - profile_id, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_custom_world_library_detail_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_library_detail_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn upsert_custom_world_profile( - &self, - input: CustomWorldProfileUpsertRecordInput, - ) -> Result { - let procedure_input = map_custom_world_profile_upsert_input(input); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .upsert_custom_world_profile_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_library_mutation_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn publish_custom_world_profile( - &self, - profile_id: String, - owner_user_id: String, - public_work_code: Option, - author_public_user_code: String, - author_display_name: String, - published_at_micros: i64, - ) -> Result { - let procedure_input = BindingCustomWorldProfilePublishInput { - profile_id, - owner_user_id, - public_work_code, - author_public_user_code, - author_display_name, - published_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .publish_custom_world_profile_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_library_mutation_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn unpublish_custom_world_profile( - &self, - profile_id: String, - owner_user_id: String, - author_display_name: String, - updated_at_micros: i64, - ) -> Result { - let procedure_input = BindingCustomWorldProfileUnpublishInput { - profile_id, - owner_user_id, - author_display_name, - updated_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .unpublish_custom_world_profile_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_library_mutation_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn delete_custom_world_profile( - &self, - profile_id: String, - owner_user_id: String, - deleted_at_micros: i64, - ) -> Result, SpacetimeClientError> { - let procedure_input = BindingCustomWorldProfileDeleteInput { - profile_id, - owner_user_id, - deleted_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .delete_custom_world_profile_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_profile_list_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn list_custom_world_gallery_entries( - &self, - ) -> Result, SpacetimeClientError> { - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .list_custom_world_gallery_entries_then(move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_gallery_list_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn get_custom_world_gallery_detail( - &self, - owner_user_id: String, - profile_id: String, - ) -> Result { - let procedure_input = BindingCustomWorldGalleryDetailInput { - owner_user_id, - profile_id, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_custom_world_gallery_detail_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_library_mutation_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn get_custom_world_gallery_detail_by_code( - &self, - public_work_code: String, - ) -> Result { - let procedure_input = BindingCustomWorldGalleryDetailByCodeInput { public_work_code }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_custom_world_gallery_detail_by_code_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_library_mutation_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn publish_custom_world_world( - &self, - input: CustomWorldPublishWorldRecordInput, - ) -> Result { - let procedure_input = map_custom_world_publish_world_input(input); - - self.call_after_connect(move |connection, sender| { - connection.procedures().publish_custom_world_world_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_publish_world_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn create_custom_world_agent_session( - &self, - input: CustomWorldAgentSessionCreateRecordInput, - ) -> Result { - let procedure_input = BindingCustomWorldAgentSessionCreateInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - seed_text: input.seed_text, - welcome_message_id: input.welcome_message_id, - welcome_message_text: input.welcome_message_text, - anchor_content_json: input.anchor_content_json, - creator_intent_json: input.creator_intent_json, - creator_intent_readiness_json: input.creator_intent_readiness_json, - anchor_pack_json: input.anchor_pack_json, - lock_state_json: input.lock_state_json, - draft_profile_json: input.draft_profile_json, - pending_clarifications_json: input.pending_clarifications_json, - suggested_actions_json: input.suggested_actions_json, - recommended_replies_json: input.recommended_replies_json, - quality_findings_json: input.quality_findings_json, - asset_coverage_json: input.asset_coverage_json, - checkpoints_json: input.checkpoints_json, - created_at_micros: input.created_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .create_custom_world_agent_session_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_agent_session_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn get_custom_world_agent_session( - &self, - session_id: String, - owner_user_id: String, - ) -> Result { - let procedure_input = BindingCustomWorldAgentSessionGetInput { - session_id, - owner_user_id, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_custom_world_agent_session_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_agent_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn list_custom_world_works( - &self, - owner_user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = BindingCustomWorldWorksListInput { owner_user_id }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().list_custom_world_works_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_works_list_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_custom_world_agent_card_detail( - &self, - session_id: String, - owner_user_id: String, - card_id: String, - ) -> Result { - let procedure_input = BindingCustomWorldAgentCardDetailGetInput { - session_id, - owner_user_id, - card_id, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_custom_world_agent_card_detail_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_draft_card_detail_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn execute_custom_world_agent_action( - &self, - input: CustomWorldAgentActionExecuteRecordInput, - ) -> Result { - let procedure_input = BindingCustomWorldAgentActionExecuteInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - operation_id: input.operation_id, - action: input.action, - payload_json: input.payload_json, - submitted_at_micros: input.submitted_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .execute_custom_world_agent_action_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_agent_action_execute_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn create_puzzle_agent_session( - &self, - input: PuzzleAgentSessionCreateRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleAgentSessionCreateInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - seed_text: input.seed_text, - welcome_message_id: input.welcome_message_id, - welcome_message_text: input.welcome_message_text, - created_at_micros: input.created_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().create_puzzle_agent_session_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_agent_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_puzzle_agent_session( - &self, - session_id: String, - owner_user_id: String, - ) -> Result { - let procedure_input = BindingPuzzleAgentSessionGetInput { - session_id, - owner_user_id, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_puzzle_agent_session_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_agent_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn submit_puzzle_agent_message( - &self, - input: PuzzleAgentMessageSubmitRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleAgentMessageSubmitInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - user_message_id: input.user_message_id, - user_message_text: input.user_message_text, - submitted_at_micros: input.submitted_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().submit_puzzle_agent_message_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_agent_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn finalize_puzzle_agent_message( - &self, - input: PuzzleAgentMessageFinalizeRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleAgentMessageFinalizeInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - assistant_message_id: input.assistant_message_id, - assistant_reply_text: input.assistant_reply_text, - stage: parse_puzzle_agent_stage_record(input.stage.as_str())?, - progress_percent: input.progress_percent, - anchor_pack_json: input.anchor_pack_json, - error_message: input.error_message, - updated_at_micros: input.updated_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .finalize_puzzle_agent_message_turn_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_agent_session_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn compile_puzzle_agent_draft( - &self, - session_id: String, - owner_user_id: String, - compiled_at_micros: i64, - ) -> Result { - let procedure_input = BindingPuzzleDraftCompileInput { - session_id, - owner_user_id, - compiled_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().compile_puzzle_agent_draft_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_agent_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn save_puzzle_generated_images( - &self, - input: PuzzleGeneratedImagesSaveRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleGeneratedImagesSaveInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - candidates_json: input.candidates_json, - saved_at_micros: input.saved_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().save_puzzle_generated_images_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_agent_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn select_puzzle_cover_image( - &self, - input: PuzzleSelectCoverImageRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleSelectCoverImageInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - candidate_id: input.candidate_id, - selected_at_micros: input.selected_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().select_puzzle_cover_image_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_agent_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn publish_puzzle_work( - &self, - input: PuzzlePublishRecordInput, - ) -> Result { - let procedure_input = BindingPuzzlePublishInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - work_id: input.work_id, - profile_id: input.profile_id, - author_display_name: input.author_display_name, - level_name: input.level_name, - summary: input.summary, - theme_tags: input.theme_tags, - published_at_micros: input.published_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .publish_puzzle_work_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_work_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn list_puzzle_works( - &self, - owner_user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = BindingPuzzleWorksListInput { owner_user_id }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .list_puzzle_works_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_works_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn get_puzzle_work_detail( - &self, - profile_id: String, - ) -> Result { - let procedure_input = BindingPuzzleWorkGetInput { profile_id }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_puzzle_work_detail_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_work_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn update_puzzle_work( - &self, - input: PuzzleWorkUpsertRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleWorkUpsertInput { - profile_id: input.profile_id, - owner_user_id: input.owner_user_id, - level_name: input.level_name, - summary: input.summary, - theme_tags: input.theme_tags, - cover_image_src: input.cover_image_src, - cover_asset_id: input.cover_asset_id, - updated_at_micros: input.updated_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .update_puzzle_work_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_work_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn list_puzzle_gallery( - &self, - ) -> Result, SpacetimeClientError> { - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .list_puzzle_gallery_then(move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_works_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn get_puzzle_gallery_detail( - &self, - profile_id: String, - ) -> Result { - let procedure_input = BindingPuzzleWorkGetInput { profile_id }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_puzzle_gallery_detail_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_work_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn start_puzzle_run( - &self, - input: PuzzleRunStartRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleRunStartInput { - run_id: input.run_id, - owner_user_id: input.owner_user_id, - profile_id: input.profile_id, - started_at_micros: input.started_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .start_puzzle_run_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_run_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn get_puzzle_run( - &self, - run_id: String, - owner_user_id: String, - ) -> Result { - let procedure_input = BindingPuzzleRunGetInput { - run_id, - owner_user_id, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_puzzle_run_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_run_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn swap_puzzle_pieces( - &self, - input: PuzzleRunSwapRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleRunSwapInput { - run_id: input.run_id, - owner_user_id: input.owner_user_id, - first_piece_id: input.first_piece_id, - second_piece_id: input.second_piece_id, - swapped_at_micros: input.swapped_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .swap_puzzle_pieces_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_run_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn drag_puzzle_piece_or_group( - &self, - input: PuzzleRunDragRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleRunDragInput { - run_id: input.run_id, - owner_user_id: input.owner_user_id, - piece_id: input.piece_id, - target_row: input.target_row, - target_col: input.target_col, - dragged_at_micros: input.dragged_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().drag_puzzle_piece_or_group_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_run_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn advance_puzzle_next_level( - &self, - input: PuzzleRunNextLevelRecordInput, - ) -> Result { - let procedure_input = BindingPuzzleRunNextLevelInput { - run_id: input.run_id, - owner_user_id: input.owner_user_id, - advanced_at_micros: input.advanced_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().advance_puzzle_next_level_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_puzzle_run_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn create_big_fish_session( - &self, - input: BigFishSessionCreateRecordInput, - ) -> Result { - let procedure_input = BindingBigFishSessionCreateInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - seed_text: input.seed_text, - welcome_message_id: input.welcome_message_id, - welcome_message_text: input.welcome_message_text, - created_at_micros: input.created_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().create_big_fish_session_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_big_fish_session( - &self, - session_id: String, - owner_user_id: String, - ) -> Result { - let procedure_input = BindingBigFishSessionGetInput { - session_id, - owner_user_id, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_big_fish_session_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_session_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn list_big_fish_works( - &self, - owner_user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = BindingBigFishWorksListInput { owner_user_id }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .list_big_fish_works_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_works_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn submit_big_fish_message( - &self, - input: BigFishMessageSubmitRecordInput, - ) -> Result { - let procedure_input = BindingBigFishMessageSubmitInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - user_message_id: input.user_message_id, - user_message_text: input.user_message_text, - assistant_message_id: input.assistant_message_id, - submitted_at_micros: input.submitted_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().submit_big_fish_message_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn finalize_big_fish_agent_message( - &self, - input: BigFishMessageFinalizeRecordInput, - ) -> Result { - let procedure_input = BindingBigFishMessageFinalizeInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - assistant_message_id: input.assistant_message_id, - assistant_reply_text: input.assistant_reply_text, - stage: parse_big_fish_creation_stage_record(input.stage.as_str())?, - progress_percent: input.progress_percent, - anchor_pack_json: input.anchor_pack_json, - error_message: input.error_message, - updated_at_micros: input.updated_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .finalize_big_fish_agent_message_turn_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_session_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn compile_big_fish_draft( - &self, - session_id: String, - owner_user_id: String, - compiled_at_micros: i64, - ) -> Result { - let procedure_input = BindingBigFishDraftCompileInput { - session_id, - owner_user_id, - compiled_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().compile_big_fish_draft_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn generate_big_fish_asset( - &self, - input: BigFishAssetGenerateRecordInput, - ) -> Result { - let procedure_input = BindingBigFishAssetGenerateInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - asset_kind: map_big_fish_asset_kind_input(input.asset_kind.as_str())?, - level: input.level, - motion_key: input.motion_key, - asset_url: input.asset_url, - generated_at_micros: input.generated_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().generate_big_fish_asset_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn publish_big_fish_game( - &self, - session_id: String, - owner_user_id: String, - published_at_micros: i64, - ) -> Result { - let procedure_input = BindingBigFishPublishInput { - session_id, - owner_user_id, - published_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().publish_big_fish_game_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn start_big_fish_run( - &self, - input: BigFishRunStartRecordInput, - ) -> Result { - let procedure_input = BindingBigFishRunStartInput { - run_id: input.run_id, - session_id: input.session_id, - owner_user_id: input.owner_user_id, - started_at_micros: input.started_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .start_big_fish_run_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_run_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn submit_big_fish_input( - &self, - input: BigFishRunInputSubmitRecordInput, - ) -> Result { - let procedure_input = BindingBigFishRunInputSubmitInput { - run_id: input.run_id, - owner_user_id: input.owner_user_id, - input_x: input.input_x, - input_y: input.input_y, - submitted_at_micros: input.submitted_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection.procedures().submit_big_fish_input_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_run_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_big_fish_run( - &self, - run_id: String, - owner_user_id: String, - ) -> Result { - let procedure_input = BindingBigFishRunGetInput { - run_id, - owner_user_id, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_big_fish_run_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_big_fish_run_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn submit_custom_world_agent_message( - &self, - input: CustomWorldAgentMessageSubmitRecordInput, - ) -> Result { - let procedure_input = BindingCustomWorldAgentMessageSubmitInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - user_message_id: input.user_message_id, - user_message_text: input.user_message_text, - operation_id: input.operation_id, - submitted_at_micros: input.submitted_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .submit_custom_world_agent_message_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_agent_operation_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn finalize_custom_world_agent_message( - &self, - input: CustomWorldAgentMessageFinalizeRecordInput, - ) -> Result { - let procedure_input = BindingCustomWorldAgentMessageFinalizeInput { - session_id: input.session_id, - owner_user_id: input.owner_user_id, - operation_id: input.operation_id, - assistant_message_id: input.assistant_message_id, - assistant_reply_text: input.assistant_reply_text, - phase_label: input.phase_label, - phase_detail: input.phase_detail, - operation_status: parse_rpg_agent_operation_status_record( - input.operation_status.as_str(), - )?, - operation_progress: input.operation_progress, - stage: parse_rpg_agent_stage_record(input.stage.as_str())?, - progress_percent: input.progress_percent, - focus_card_id: input.focus_card_id, - anchor_content_json: input.anchor_content_json, - creator_intent_json: input.creator_intent_json, - creator_intent_readiness_json: input.creator_intent_readiness_json, - anchor_pack_json: input.anchor_pack_json, - draft_profile_json: input.draft_profile_json, - pending_clarifications_json: input.pending_clarifications_json, - suggested_actions_json: input.suggested_actions_json, - recommended_replies_json: input.recommended_replies_json, - quality_findings_json: input.quality_findings_json, - asset_coverage_json: input.asset_coverage_json, - error_message: input.error_message, - updated_at_micros: input.updated_at_micros, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .finalize_custom_world_agent_message_turn_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_agent_operation_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_custom_world_agent_operation( - &self, - session_id: String, - owner_user_id: String, - operation_id: String, - ) -> Result { - let procedure_input = BindingCustomWorldAgentOperationGetInput { - session_id, - owner_user_id, - operation_id, - }; - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_custom_world_agent_operation_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_custom_world_agent_operation_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn list_platform_browse_history( - &self, - user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_browse_history_list_input( - build_runtime_browse_history_list_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().list_platform_browse_history_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_browse_history_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_profile_dashboard( - &self, - user_id: String, - ) -> Result { - let procedure_input = map_runtime_profile_dashboard_get_input( - build_runtime_profile_dashboard_get_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_profile_dashboard_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_profile_dashboard_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn list_profile_wallet_ledger( - &self, - user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_profile_wallet_ledger_list_input( - build_runtime_profile_wallet_ledger_list_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().list_profile_wallet_ledger_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_profile_wallet_ledger_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_profile_play_stats( - &self, - user_id: String, - ) -> Result { - let procedure_input = map_runtime_profile_play_stats_get_input( - build_runtime_profile_play_stats_get_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_profile_play_stats_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_profile_play_stats_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_runtime_snapshot( - &self, - user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_snapshot_get_input( - build_runtime_snapshot_get_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_runtime_snapshot_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_snapshot_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn put_runtime_snapshot( - &self, - user_id: String, - saved_at_micros: i64, - bottom_tab: String, - game_state: serde_json::Value, - current_story: Option, - updated_at_micros: i64, - ) -> Result { - let procedure_input = map_runtime_snapshot_upsert_input( - build_runtime_snapshot_upsert_input( - user_id, - saved_at_micros, - bottom_tab, - game_state, - current_story, - updated_at_micros, - ) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .upsert_runtime_snapshot_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_snapshot_required_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn delete_runtime_snapshot( - &self, - user_id: String, - ) -> Result { - let procedure_input = map_runtime_snapshot_delete_input( - build_runtime_snapshot_delete_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .delete_runtime_snapshot_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_snapshot_delete_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn list_profile_save_archives( - &self, - user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_profile_save_archive_list_input( - build_runtime_profile_save_archive_list_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().list_profile_save_archives_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_profile_save_archive_list_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn resume_profile_save_archive( - &self, - user_id: String, - world_key: String, - ) -> Result<(RuntimeProfileSaveArchiveRecord, RuntimeSnapshotRecord), SpacetimeClientError> - { - let procedure_input = map_runtime_profile_save_archive_resume_input( - build_runtime_profile_save_archive_resume_input(user_id, world_key) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .resume_profile_save_archive_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_profile_save_archive_resume_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn begin_story_session( - &self, - story_session_id: String, - runtime_session_id: String, - actor_user_id: String, - world_profile_id: String, - initial_prompt: String, - opening_summary: Option, - created_at_micros: i64, - ) -> Result { - let procedure_input = map_story_session_input( - build_story_session_input( - story_session_id, - runtime_session_id, - actor_user_id, - world_profile_id, - initial_prompt, - opening_summary, - created_at_micros, - ) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().begin_story_session_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_story_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn create_battle_state( - &self, - input: DomainBattleStateInput, - ) -> Result { - validate_battle_state_input(&input) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?; - let procedure_input = map_battle_state_input(input); - - self.call_after_connect(move |connection, sender| { - connection.procedures().create_battle_state_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_battle_state_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_battle_state( - &self, - battle_state_id: String, - ) -> Result { - let procedure_input = map_battle_state_query_input( - build_battle_state_query_input(battle_state_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .get_battle_state_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_battle_state_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn get_runtime_inventory_state( - &self, - runtime_session_id: String, - actor_user_id: String, - ) -> Result { - let procedure_input = map_runtime_inventory_state_query_input( - build_runtime_inventory_state_query_input(runtime_session_id, actor_user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_runtime_inventory_state_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_inventory_state_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn resolve_npc_battle_interaction( - &self, - input: ResolveNpcBattleInteractionInput, - ) -> Result { - validate_npc_battle_interaction_input(&input)?; - let procedure_input = map_resolve_npc_battle_interaction_input(input); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .resolve_npc_battle_interaction_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_npc_battle_interaction_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn continue_story( - &self, - story_session_id: String, - event_id: String, - narrative_text: String, - choice_function_id: Option, - updated_at_micros: i64, - ) -> Result { - let procedure_input = map_story_continue_input( - build_story_continue_input( - story_session_id, - event_id, - narrative_text, - choice_function_id, - updated_at_micros, - ) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().continue_story_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_story_session_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn get_story_session_state( - &self, - story_session_id: String, - ) -> Result { - let procedure_input = map_story_session_state_input( - build_story_session_state_input(story_session_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection.procedures().get_story_session_state_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_story_session_state_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn resolve_combat_action( - &self, - input: DomainResolveCombatActionInput, - ) -> Result { - validate_resolve_combat_action_input(&input) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?; - let procedure_input = map_resolve_combat_action_input(input); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .resolve_combat_action_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_resolve_combat_action_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn put_runtime_settings( - &self, - user_id: String, - music_volume: f32, - platform_theme: RuntimePlatformTheme, - updated_at_micros: i64, - ) -> Result { - let procedure_input = map_runtime_setting_upsert_input( - build_runtime_setting_upsert_input( - user_id, - music_volume, - platform_theme, - updated_at_micros, - ) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .upsert_runtime_setting_and_return_then(procedure_input, move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_setting_procedure_result); - send_once(&sender, mapped); - }); - }) - .await - } - - pub async fn upsert_platform_browse_history_entries( - &self, - user_id: String, - entries: Vec, - updated_at_micros: i64, - ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_browse_history_sync_input( - build_runtime_browse_history_sync_input(user_id, entries, updated_at_micros) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .upsert_platform_browse_history_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_browse_history_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - - pub async fn clear_platform_browse_history( - &self, - user_id: String, - ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_browse_history_clear_input( - build_runtime_browse_history_clear_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); - - self.call_after_connect(move |connection, sender| { - connection - .procedures() - .clear_platform_browse_history_and_return_then( - procedure_input, - move |_, result| { - let mapped = result - .map_err(|error| SpacetimeClientError::Procedure(error.to_string())) - .and_then(map_runtime_browse_history_procedure_result); - send_once(&sender, mapped); - }, - ); - }) - .await - } - -======= ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) async fn call_after_connect( &self, call: impl FnOnce(&DbConnection, ProcedureResultSender) + Send + 'static, @@ -2626,4502 +439,6 @@ fn send_connect_once( } } -<<<<<<< HEAD -fn map_entity_binding_input( - input: module_assets::AssetEntityBindingInput, -) -> BindingAssetEntityBindingInput { - BindingAssetEntityBindingInput { - binding_id: input.binding_id, - asset_object_id: input.asset_object_id, - entity_kind: input.entity_kind, - entity_id: input.entity_id, - slot: input.slot, - asset_kind: input.asset_kind, - owner_user_id: input.owner_user_id, - profile_id: input.profile_id, - updated_at_micros: input.updated_at_micros, - } -} - -fn map_upsert_input(input: module_assets::AssetObjectUpsertInput) -> BindingAssetObjectUpsertInput { - BindingAssetObjectUpsertInput { - asset_object_id: input.asset_object_id, - bucket: input.bucket, - object_key: input.object_key, - access_policy: map_access_policy(input.access_policy), - content_type: input.content_type, - content_length: input.content_length, - content_hash: input.content_hash, - version: input.version, - source_job_id: input.source_job_id, - owner_user_id: input.owner_user_id, - profile_id: input.profile_id, - entity_id: input.entity_id, - asset_kind: input.asset_kind, - updated_at_micros: input.updated_at_micros, - } -} - -fn map_runtime_setting_get_input( - input: module_runtime::RuntimeSettingGetInput, -) -> BindingRuntimeSettingGetInput { - BindingRuntimeSettingGetInput { - user_id: input.user_id, - } -} - -fn map_runtime_setting_upsert_input( - input: module_runtime::RuntimeSettingUpsertInput, -) -> BindingRuntimeSettingUpsertInput { - BindingRuntimeSettingUpsertInput { - user_id: input.user_id, - music_volume: input.music_volume, - platform_theme: map_runtime_platform_theme(input.platform_theme), - updated_at_micros: input.updated_at_micros, - } -} - -fn map_runtime_browse_history_list_input( - input: module_runtime::RuntimeBrowseHistoryListInput, -) -> BindingRuntimeBrowseHistoryListInput { - BindingRuntimeBrowseHistoryListInput { - user_id: input.user_id, - } -} - -fn map_runtime_browse_history_clear_input( - input: module_runtime::RuntimeBrowseHistoryClearInput, -) -> BindingRuntimeBrowseHistoryClearInput { - BindingRuntimeBrowseHistoryClearInput { - user_id: input.user_id, - } -} - -fn map_runtime_browse_history_sync_input( - input: module_runtime::RuntimeBrowseHistorySyncInput, -) -> BindingRuntimeBrowseHistorySyncInput { - BindingRuntimeBrowseHistorySyncInput { - user_id: input.user_id, - entries: input - .entries - .into_iter() - .map(map_runtime_browse_history_write_input) - .collect(), - updated_at_micros: input.updated_at_micros, - } -} - -fn map_runtime_browse_history_write_input( - input: module_runtime::RuntimeBrowseHistoryWriteInput, -) -> BindingRuntimeBrowseHistoryWriteInput { - BindingRuntimeBrowseHistoryWriteInput { - owner_user_id: input.owner_user_id, - profile_id: input.profile_id, - world_name: input.world_name, - subtitle: input.subtitle, - summary_text: input.summary_text, - cover_image_src: input.cover_image_src, - theme_mode: input.theme_mode, - author_display_name: input.author_display_name, - visited_at: input.visited_at, - } -} - -fn map_runtime_profile_dashboard_get_input( - input: module_runtime::RuntimeProfileDashboardGetInput, -) -> BindingRuntimeProfileDashboardGetInput { - BindingRuntimeProfileDashboardGetInput { - user_id: input.user_id, - } -} - -fn map_runtime_profile_wallet_ledger_list_input( - input: module_runtime::RuntimeProfileWalletLedgerListInput, -) -> BindingRuntimeProfileWalletLedgerListInput { - BindingRuntimeProfileWalletLedgerListInput { - user_id: input.user_id, - } -} - -fn map_runtime_profile_play_stats_get_input( - input: module_runtime::RuntimeProfilePlayStatsGetInput, -) -> BindingRuntimeProfilePlayStatsGetInput { - BindingRuntimeProfilePlayStatsGetInput { - user_id: input.user_id, - } -} - -fn map_runtime_snapshot_get_input( - input: module_runtime::RuntimeSnapshotGetInput, -) -> BindingRuntimeSnapshotGetInput { - BindingRuntimeSnapshotGetInput { - user_id: input.user_id, - } -} - -fn map_runtime_snapshot_upsert_input( - input: module_runtime::RuntimeSnapshotUpsertInput, -) -> BindingRuntimeSnapshotUpsertInput { - BindingRuntimeSnapshotUpsertInput { - user_id: input.user_id, - saved_at_micros: input.saved_at_micros, - bottom_tab: input.bottom_tab, - game_state_json: input.game_state_json, - current_story_json: input.current_story_json, - updated_at_micros: input.updated_at_micros, - } -} - -fn map_runtime_snapshot_delete_input( - input: module_runtime::RuntimeSnapshotDeleteInput, -) -> BindingRuntimeSnapshotDeleteInput { - BindingRuntimeSnapshotDeleteInput { - user_id: input.user_id, - } -} - -fn map_runtime_profile_save_archive_list_input( - input: module_runtime::RuntimeProfileSaveArchiveListInput, -) -> BindingRuntimeProfileSaveArchiveListInput { - BindingRuntimeProfileSaveArchiveListInput { - user_id: input.user_id, - } -} - -fn map_runtime_profile_save_archive_resume_input( - input: module_runtime::RuntimeProfileSaveArchiveResumeInput, -) -> BindingRuntimeProfileSaveArchiveResumeInput { - BindingRuntimeProfileSaveArchiveResumeInput { - user_id: input.user_id, - world_key: input.world_key, - } -} - -fn map_ai_task_create_input(input: DomainAiTaskCreateInput) -> BindingAiTaskCreateInput { - BindingAiTaskCreateInput { - task_id: input.task_id, - task_kind: map_ai_task_kind(input.task_kind), - owner_user_id: input.owner_user_id, - request_label: input.request_label, - source_module: input.source_module, - source_entity_id: input.source_entity_id, - request_payload_json: input.request_payload_json, - stages: input - .stages - .into_iter() - .map(map_ai_task_stage_blueprint) - .collect(), - created_at_micros: input.created_at_micros, - } -} - -fn map_ai_task_start_input(input: DomainAiTaskStartInput) -> BindingAiTaskStartInput { - BindingAiTaskStartInput { - task_id: input.task_id, - started_at_micros: input.started_at_micros, - } -} - -fn map_ai_task_stage_start_input( - input: DomainAiTaskStageStartInput, -) -> BindingAiTaskStageStartInput { - BindingAiTaskStageStartInput { - task_id: input.task_id, - stage_kind: map_ai_task_stage_kind(input.stage_kind), - started_at_micros: input.started_at_micros, - } -} - -fn map_ai_text_chunk_append_input( - input: DomainAiTextChunkAppendInput, -) -> BindingAiTextChunkAppendInput { - BindingAiTextChunkAppendInput { - task_id: input.task_id, - stage_kind: map_ai_task_stage_kind(input.stage_kind), - sequence: input.sequence, - delta_text: input.delta_text, - created_at_micros: input.created_at_micros, - } -} - -fn map_ai_stage_completion_input( - input: DomainAiStageCompletionInput, -) -> BindingAiStageCompletionInput { - BindingAiStageCompletionInput { - task_id: input.task_id, - stage_kind: map_ai_task_stage_kind(input.stage_kind), - text_output: input.text_output, - structured_payload_json: input.structured_payload_json, - warning_messages: input.warning_messages, - completed_at_micros: input.completed_at_micros, - } -} - -fn map_ai_result_reference_input( - input: DomainAiResultReferenceInput, -) -> BindingAiResultReferenceInput { - BindingAiResultReferenceInput { - task_id: input.task_id, - reference_kind: map_ai_result_reference_kind(input.reference_kind), - reference_id: input.reference_id, - label: input.label, - created_at_micros: input.created_at_micros, - } -} - -fn map_ai_task_finish_input(input: DomainAiTaskFinishInput) -> BindingAiTaskFinishInput { - BindingAiTaskFinishInput { - task_id: input.task_id, - completed_at_micros: input.completed_at_micros, - } -} - -fn map_ai_task_failure_input(input: DomainAiTaskFailureInput) -> BindingAiTaskFailureInput { - BindingAiTaskFailureInput { - task_id: input.task_id, - failure_message: input.failure_message, - completed_at_micros: input.completed_at_micros, - } -} - -fn map_ai_task_cancel_input(input: DomainAiTaskCancelInput) -> BindingAiTaskCancelInput { - BindingAiTaskCancelInput { - task_id: input.task_id, - completed_at_micros: input.completed_at_micros, - } -} - -fn map_ai_task_stage_blueprint( - blueprint: DomainAiTaskStageBlueprint, -) -> BindingAiTaskStageBlueprint { - BindingAiTaskStageBlueprint { - stage_kind: map_ai_task_stage_kind(blueprint.stage_kind), - label: blueprint.label, - detail: blueprint.detail, - order: blueprint.order, - } -} - -fn map_custom_world_profile_upsert_input( - input: CustomWorldProfileUpsertRecordInput, -) -> BindingCustomWorldProfileUpsertInput { - BindingCustomWorldProfileUpsertInput { - profile_id: input.profile_id, - owner_user_id: input.owner_user_id, - public_work_code: input.public_work_code, - author_public_user_code: input.author_public_user_code, - source_agent_session_id: input.source_agent_session_id, - world_name: input.world_name, - subtitle: input.subtitle, - summary_text: input.summary_text, - theme_mode: map_custom_world_theme_mode(input.theme_mode), - cover_image_src: input.cover_image_src, - profile_payload_json: input.profile_payload_json, - playable_npc_count: input.playable_npc_count, - landmark_count: input.landmark_count, - author_display_name: input.author_display_name, - updated_at_micros: input.updated_at_micros, - } -} - -fn map_custom_world_publish_world_input( - input: CustomWorldPublishWorldRecordInput, -) -> BindingCustomWorldPublishWorldInput { - BindingCustomWorldPublishWorldInput { - session_id: input.session_id, - profile_id: input.profile_id, - owner_user_id: input.owner_user_id, - public_work_code: input.public_work_code, - author_public_user_code: input.author_public_user_code, - draft_profile_json: input.draft_profile_json, - legacy_result_profile_json: input.legacy_result_profile_json, - setting_text: input.setting_text, - author_display_name: input.author_display_name, - published_at_micros: input.published_at_micros, - } -} - -fn map_story_session_input(input: DomainStorySessionInput) -> BindingStorySessionInput { - BindingStorySessionInput { - story_session_id: input.story_session_id, - runtime_session_id: input.runtime_session_id, - actor_user_id: input.actor_user_id, - world_profile_id: input.world_profile_id, - initial_prompt: input.initial_prompt, - opening_summary: input.opening_summary, - created_at_micros: input.created_at_micros, - } -} - -fn map_story_continue_input(input: DomainStoryContinueInput) -> BindingStoryContinueInput { - BindingStoryContinueInput { - story_session_id: input.story_session_id, - event_id: input.event_id, - narrative_text: input.narrative_text, - choice_function_id: input.choice_function_id, - updated_at_micros: input.updated_at_micros, - } -} - -fn map_story_session_state_input( - input: DomainStorySessionStateInput, -) -> BindingStorySessionStateInput { - BindingStorySessionStateInput { - story_session_id: input.story_session_id, - } -} - -fn map_runtime_inventory_state_query_input( - input: DomainRuntimeInventoryStateQueryInput, -) -> BindingRuntimeInventoryStateQueryInput { - BindingRuntimeInventoryStateQueryInput { - runtime_session_id: input.runtime_session_id, - actor_user_id: input.actor_user_id, - } -} - -fn map_battle_state_query_input( - input: DomainBattleStateQueryInput, -) -> BindingBattleStateQueryInput { - BindingBattleStateQueryInput { - battle_state_id: input.battle_state_id, - } -} - -fn map_battle_state_input(input: DomainBattleStateInput) -> BindingBattleStateInput { - BindingBattleStateInput { - battle_state_id: input.battle_state_id, - story_session_id: input.story_session_id, - runtime_session_id: input.runtime_session_id, - actor_user_id: input.actor_user_id, - chapter_id: input.chapter_id, - target_npc_id: input.target_npc_id, - target_name: input.target_name, - battle_mode: map_battle_mode(input.battle_mode), - player_hp: input.player_hp, - player_max_hp: input.player_max_hp, - player_mana: input.player_mana, - player_max_mana: input.player_max_mana, - target_hp: input.target_hp, - target_max_hp: input.target_max_hp, - experience_reward: input.experience_reward, - reward_items: input - .reward_items - .into_iter() - .map(map_runtime_item_reward_item_snapshot) - .collect(), - created_at_micros: input.created_at_micros, - } -} - -fn map_resolve_combat_action_input( - input: DomainResolveCombatActionInput, -) -> BindingResolveCombatActionInput { - BindingResolveCombatActionInput { - battle_state_id: input.battle_state_id, - function_id: input.function_id, - action_text: input.action_text, - base_damage: input.base_damage, - mana_cost: input.mana_cost, - heal: input.heal, - mana_restore: input.mana_restore, - counter_multiplier_basis_points: input.counter_multiplier_basis_points, - updated_at_micros: input.updated_at_micros, - } -} - -fn map_procedure_result( - result: BindingAssetObjectProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let snapshot = result.record.ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回对象快照".to_string()) - })?; - - Ok(build_asset_object_record(map_snapshot(snapshot))) -} - -fn map_entity_binding_procedure_result( - result: BindingAssetEntityBindingProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let snapshot = result.record.ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回绑定快照".to_string()) - })?; - - Ok(build_asset_entity_binding_record( - map_entity_binding_snapshot(snapshot), - )) -} - -fn map_runtime_setting_procedure_result( - result: BindingRuntimeSettingProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let snapshot = result.record.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 runtime settings 快照".to_string(), - ) - })?; - - Ok(build_runtime_setting_record(map_runtime_setting_snapshot( - snapshot, - ))) -} - -fn map_runtime_browse_history_procedure_result( - result: BindingRuntimeBrowseHistoryProcedureResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - Ok(result - .entries - .into_iter() - .map(|snapshot| { - build_runtime_browse_history_record(map_runtime_browse_history_snapshot(snapshot)) - }) - .collect()) -} - -fn map_runtime_profile_dashboard_procedure_result( - result: BindingRuntimeProfileDashboardProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let snapshot = result.record.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 profile dashboard 快照".to_string(), - ) - })?; - - Ok(build_runtime_profile_dashboard_record( - map_runtime_profile_dashboard_snapshot(snapshot), - )) -} - -fn map_runtime_profile_wallet_ledger_procedure_result( - result: BindingRuntimeProfileWalletLedgerProcedureResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - Ok(result - .entries - .into_iter() - .map(|snapshot| { - build_runtime_profile_wallet_ledger_entry_record( - map_runtime_profile_wallet_ledger_entry_snapshot(snapshot), - ) - }) - .collect()) -} - -fn map_runtime_profile_play_stats_procedure_result( - result: BindingRuntimeProfilePlayStatsProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let snapshot = result.record.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 profile play stats 快照".to_string(), - ) - })?; - - Ok(build_runtime_profile_play_stats_record( - map_runtime_profile_play_stats_snapshot(snapshot), - )) -} - -fn map_runtime_snapshot_procedure_result( - result: BindingRuntimeSnapshotProcedureResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - result - .record - .map(|snapshot| { - build_runtime_snapshot_record(map_runtime_snapshot_snapshot(snapshot)) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string())) - }) - .transpose() -} - -fn map_runtime_snapshot_required_procedure_result( - result: BindingRuntimeSnapshotProcedureResult, -) -> Result { - map_runtime_snapshot_procedure_result(result)?.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 runtime snapshot 快照".to_string(), - ) - }) -} - -fn map_runtime_snapshot_delete_procedure_result( - result: BindingRuntimeSnapshotProcedureResult, -) -> Result { - map_runtime_snapshot_procedure_result(result).map(|record| record.is_some()) -} - -fn map_runtime_profile_save_archive_list_procedure_result( - result: BindingRuntimeProfileSaveArchiveProcedureResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - result - .entries - .into_iter() - .map(|snapshot| { - build_runtime_profile_save_archive_record(map_runtime_profile_save_archive_snapshot( - snapshot, - )) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string())) - }) - .collect() -} - -fn map_runtime_profile_save_archive_resume_procedure_result( - result: BindingRuntimeProfileSaveArchiveProcedureResult, -) -> Result<(RuntimeProfileSaveArchiveRecord, RuntimeSnapshotRecord), SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let archive = result.record.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 save archive 快照".to_string(), - ) - })?; - let snapshot = result.current_snapshot.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回恢复后的 runtime snapshot".to_string(), - ) - })?; - - Ok(( - build_runtime_profile_save_archive_record(map_runtime_profile_save_archive_snapshot( - archive, - )) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - build_runtime_snapshot_record(map_runtime_snapshot_snapshot(snapshot)) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - )) -} - -fn map_ai_task_procedure_result( - result: BindingAiTaskProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Runtime( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let task = result.task.ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 ai_task 快照".to_string()) - })?; - - Ok(AiTaskMutationRecord { - task: map_ai_task_snapshot(task), - text_chunk: result.text_chunk.map(map_ai_text_chunk_snapshot), - }) -} - -fn map_custom_world_profile_list_result( - result: BindingCustomWorldProfileListResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - result - .entries - .into_iter() - .map(map_custom_world_library_entry_from_profile_snapshot) - .collect() -} - -fn map_custom_world_library_detail_result( - result: BindingCustomWorldLibraryMutationResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let entry = result - .entry - .ok_or_else(|| SpacetimeClientError::Procedure("custom_world_profile 不存在".to_string())) - .and_then(map_custom_world_library_entry_from_profile_snapshot)?; - let gallery_entry = result - .gallery_entry - .map(map_custom_world_gallery_entry_snapshot) - .transpose()?; - - Ok(CustomWorldLibraryMutationRecord { - entry, - gallery_entry, - }) -} - -fn map_custom_world_gallery_list_result( - result: BindingCustomWorldGalleryListResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - Ok(result - .entries - .into_iter() - .map(map_custom_world_gallery_entry_snapshot) - .collect::, _>>()?) -} - -fn map_custom_world_library_mutation_result( - result: BindingCustomWorldLibraryMutationResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let entry = result - .entry - .ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB 未返回 custom world entry".to_string()) - }) - .and_then(map_custom_world_library_entry_from_profile_snapshot)?; - let gallery_entry = result - .gallery_entry - .map(map_custom_world_gallery_entry_snapshot) - .transpose()?; - - Ok(CustomWorldLibraryMutationRecord { - entry, - gallery_entry, - }) -} - -fn map_custom_world_publish_world_result( - result: BindingCustomWorldPublishWorldResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let compiled_record = result - .compiled_record - .ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 published profile compile 快照".to_string(), - ) - }) - .and_then(map_custom_world_published_profile_compile_snapshot)?; - let entry = result - .entry - .ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB 未返回 custom world entry".to_string()) - }) - .and_then(map_custom_world_library_entry_from_profile_snapshot)?; - let gallery_entry = result - .gallery_entry - .map(map_custom_world_gallery_entry_snapshot) - .transpose()?; - let session_stage = result - .session_stage - .ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB 未返回 session stage".to_string()) - }) - .map(map_rpg_agent_stage)?; - - Ok(CustomWorldPublishWorldRecord { - compiled_record, - entry, - gallery_entry, - session_stage, - }) -} - -fn map_custom_world_agent_session_procedure_result( - result: BindingCustomWorldAgentSessionProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let session = result.session.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 custom world agent session 快照".to_string(), - ) - })?; - - map_custom_world_agent_session_snapshot(session) -} - -fn map_custom_world_agent_operation_procedure_result( - result: BindingCustomWorldAgentOperationProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let operation = result.operation.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 custom world agent operation 快照".to_string(), - ) - })?; - - Ok(map_custom_world_agent_operation_snapshot(operation)) -} - -fn map_custom_world_works_list_result( - result: BindingCustomWorldWorksListResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - result - .items - .into_iter() - .map(map_custom_world_work_summary_snapshot) - .collect() -} - -fn map_custom_world_draft_card_detail_result( - result: BindingCustomWorldDraftCardDetailResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let card = result.card.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 custom world card detail 快照".to_string(), - ) - })?; - - map_custom_world_draft_card_detail_snapshot(card) -} - -fn map_custom_world_agent_action_execute_result( - result: BindingCustomWorldAgentActionExecuteResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let operation = result.operation.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 custom world action operation 快照".to_string(), - ) - })?; - - Ok(CustomWorldAgentActionExecuteRecord { - operation: map_custom_world_agent_operation_snapshot(operation), - }) -} - -fn map_puzzle_agent_session_procedure_result( - result: BindingPuzzleAgentSessionProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let session_json = result.session_json.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 puzzle agent session 快照".to_string(), - ) - })?; - let session: DomainPuzzleAgentSessionSnapshot = - serde_json::from_str(&session_json).map_err(|error| { - SpacetimeClientError::Runtime(format!("puzzle agent session_json 非法: {error}")) - })?; - Ok(map_puzzle_agent_session_snapshot(session)) -} - -fn map_puzzle_work_procedure_result( - result: BindingPuzzleWorkProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let item_json = result.item_json.ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 puzzle work 快照".to_string()) - })?; - let item: DomainPuzzleWorkProfile = serde_json::from_str(&item_json).map_err(|error| { - SpacetimeClientError::Runtime(format!("puzzle work item_json 非法: {error}")) - })?; - Ok(map_puzzle_work_profile(item)) -} - -fn map_puzzle_works_procedure_result( - result: BindingPuzzleWorksProcedureResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let items_json = result.items_json.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 puzzle works 快照".to_string(), - ) - })?; - let items: Vec = - serde_json::from_str(&items_json).map_err(|error| { - SpacetimeClientError::Runtime(format!("puzzle works items_json 非法: {error}")) - })?; - Ok(items.into_iter().map(map_puzzle_work_profile).collect()) -} - -fn map_puzzle_run_procedure_result( - result: BindingPuzzleRunProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let run_json = result.run_json.ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 puzzle run 快照".to_string()) - })?; - let run: DomainPuzzleRunSnapshot = serde_json::from_str(&run_json).map_err(|error| { - SpacetimeClientError::Runtime(format!("puzzle run run_json 非法: {error}")) - })?; - Ok(map_puzzle_run_snapshot(run)) -} - -fn map_big_fish_session_procedure_result( - result: BindingBigFishSessionProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let session = result.session.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 big fish session 快照".to_string(), - ) - })?; - - Ok(map_big_fish_session_snapshot(session)) -} - -fn map_big_fish_works_procedure_result( - result: BindingBigFishWorksProcedureResult, -) -> Result, SpacetimeClientError> { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let items_json = result.items_json.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 big fish works 快照".to_string(), - ) - })?; - serde_json::from_str::>(&items_json).map_err(|error| { - SpacetimeClientError::Runtime(format!("big fish works items_json 非法: {error}")) - }) -} - -fn map_big_fish_run_procedure_result( - result: BindingBigFishRunProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let run = result.run.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 big fish runtime 快照".to_string(), - ) - })?; - - Ok(map_big_fish_runtime_snapshot(run)) -} - -fn map_story_session_procedure_result( - result: BindingStorySessionProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let session = result.session.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 story session 快照".to_string(), - ) - })?; - let event = result.event.ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 story event 快照".to_string()) - })?; - - Ok(StorySessionResultRecord { - session: map_story_session_snapshot(session), - event: map_story_event_snapshot(event), - }) -} - -fn map_story_session_state_procedure_result( - result: BindingStorySessionStateProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let session = result.session.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 story session state 快照".to_string(), - ) - })?; - - Ok(StorySessionStateRecord { - session: map_story_session_snapshot(session), - events: result - .events - .into_iter() - .map(map_story_event_snapshot) - .collect(), - }) -} - -fn map_runtime_inventory_state_procedure_result( - result: BindingRuntimeInventoryStateProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let snapshot = result.snapshot.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 runtime inventory state 快照".to_string(), - ) - })?; - - Ok(build_runtime_inventory_state_record( - map_runtime_inventory_state_snapshot(snapshot), - )) -} - -fn map_battle_state_procedure_result( - result: BindingBattleStateProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let snapshot = result.snapshot.ok_or_else(|| { - SpacetimeClientError::Procedure( - "SpacetimeDB procedure 未返回 battle_state 快照".to_string(), - ) - })?; - - Ok(build_battle_state_record(map_battle_state_snapshot( - snapshot, - ))) -} - -fn map_resolve_combat_action_procedure_result( - result: BindingResolveCombatActionProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let action_result = result.result.ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回战斗结算结果".to_string()) - })?; - - Ok(build_resolve_combat_action_record( - map_resolve_combat_action_result(action_result), - )) -} - -fn map_npc_battle_interaction_procedure_result( - result: BindingNpcBattleInteractionProcedureResult, -) -> Result { - if !result.ok { - return Err(SpacetimeClientError::Procedure( - result - .error_message - .unwrap_or_else(|| "SpacetimeDB procedure 返回未知错误".to_string()), - )); - } - - let interaction_result = result.result.ok_or_else(|| { - SpacetimeClientError::Procedure("SpacetimeDB procedure 未返回 NPC 开战结果".to_string()) - })?; - - Ok(build_npc_battle_interaction_record( - map_npc_battle_interaction_result(interaction_result), - )) -} - -fn map_entity_binding_snapshot( - snapshot: BindingAssetEntityBindingSnapshot, -) -> module_assets::AssetEntityBindingSnapshot { - module_assets::AssetEntityBindingSnapshot { - binding_id: snapshot.binding_id, - asset_object_id: snapshot.asset_object_id, - entity_kind: snapshot.entity_kind, - entity_id: snapshot.entity_id, - slot: snapshot.slot, - asset_kind: snapshot.asset_kind, - owner_user_id: snapshot.owner_user_id, - profile_id: snapshot.profile_id, - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_snapshot( - snapshot: BindingAssetObjectUpsertSnapshot, -) -> module_assets::AssetObjectUpsertSnapshot { - module_assets::AssetObjectUpsertSnapshot { - asset_object_id: snapshot.asset_object_id, - bucket: snapshot.bucket, - object_key: snapshot.object_key, - access_policy: map_access_policy_back(snapshot.access_policy), - content_type: snapshot.content_type, - content_length: snapshot.content_length, - content_hash: snapshot.content_hash, - version: snapshot.version, - source_job_id: snapshot.source_job_id, - owner_user_id: snapshot.owner_user_id, - profile_id: snapshot.profile_id, - entity_id: snapshot.entity_id, - asset_kind: snapshot.asset_kind, - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_runtime_setting_snapshot( - snapshot: BindingRuntimeSettingSnapshot, -) -> module_runtime::RuntimeSettingSnapshot { - module_runtime::RuntimeSettingSnapshot { - user_id: snapshot.user_id, - music_volume: snapshot.music_volume, - platform_theme: map_runtime_platform_theme_back(snapshot.platform_theme), - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_runtime_browse_history_snapshot( - snapshot: BindingRuntimeBrowseHistorySnapshot, -) -> module_runtime::RuntimeBrowseHistorySnapshot { - module_runtime::RuntimeBrowseHistorySnapshot { - browse_history_id: snapshot.browse_history_id, - user_id: snapshot.user_id, - owner_user_id: snapshot.owner_user_id, - profile_id: snapshot.profile_id, - world_name: snapshot.world_name, - subtitle: snapshot.subtitle, - summary_text: snapshot.summary_text, - cover_image_src: snapshot.cover_image_src, - theme_mode: map_runtime_browse_history_theme_mode_back(snapshot.theme_mode), - author_display_name: snapshot.author_display_name, - visited_at_micros: snapshot.visited_at_micros, - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_runtime_profile_dashboard_snapshot( - snapshot: BindingRuntimeProfileDashboardSnapshot, -) -> module_runtime::RuntimeProfileDashboardSnapshot { - module_runtime::RuntimeProfileDashboardSnapshot { - user_id: snapshot.user_id, - wallet_balance: snapshot.wallet_balance, - total_play_time_ms: snapshot.total_play_time_ms, - played_world_count: snapshot.played_world_count, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_runtime_profile_wallet_ledger_entry_snapshot( - snapshot: BindingRuntimeProfileWalletLedgerEntrySnapshot, -) -> module_runtime::RuntimeProfileWalletLedgerEntrySnapshot { - module_runtime::RuntimeProfileWalletLedgerEntrySnapshot { - wallet_ledger_id: snapshot.wallet_ledger_id, - user_id: snapshot.user_id, - amount_delta: snapshot.amount_delta, - balance_after: snapshot.balance_after, - source_type: map_runtime_profile_wallet_ledger_source_type(snapshot.source_type), - created_at_micros: snapshot.created_at_micros, - } -} - -fn map_runtime_profile_played_world_snapshot( - snapshot: BindingRuntimeProfilePlayedWorldSnapshot, -) -> module_runtime::RuntimeProfilePlayedWorldSnapshot { - module_runtime::RuntimeProfilePlayedWorldSnapshot { - played_world_id: snapshot.played_world_id, - user_id: snapshot.user_id, - world_key: snapshot.world_key, - owner_user_id: snapshot.owner_user_id, - profile_id: snapshot.profile_id, - world_type: snapshot.world_type, - world_title: snapshot.world_title, - world_subtitle: snapshot.world_subtitle, - first_played_at_micros: snapshot.first_played_at_micros, - last_played_at_micros: snapshot.last_played_at_micros, - last_observed_play_time_ms: snapshot.last_observed_play_time_ms, - } -} - -fn map_runtime_profile_play_stats_snapshot( - snapshot: BindingRuntimeProfilePlayStatsSnapshot, -) -> module_runtime::RuntimeProfilePlayStatsSnapshot { - module_runtime::RuntimeProfilePlayStatsSnapshot { - user_id: snapshot.user_id, - total_play_time_ms: snapshot.total_play_time_ms, - played_works: snapshot - .played_works - .into_iter() - .map(map_runtime_profile_played_world_snapshot) - .collect(), - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_runtime_snapshot_snapshot( - snapshot: BindingRuntimeSnapshot, -) -> module_runtime::RuntimeSnapshot { - module_runtime::RuntimeSnapshot { - user_id: snapshot.user_id, - version: snapshot.version, - saved_at_micros: snapshot.saved_at_micros, - bottom_tab: snapshot.bottom_tab, - game_state_json: snapshot.game_state_json, - current_story_json: snapshot.current_story_json, - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_runtime_profile_save_archive_snapshot( - snapshot: BindingRuntimeProfileSaveArchiveSnapshot, -) -> module_runtime::RuntimeProfileSaveArchiveSnapshot { - module_runtime::RuntimeProfileSaveArchiveSnapshot { - archive_id: snapshot.archive_id, - user_id: snapshot.user_id, - world_key: snapshot.world_key, - owner_user_id: snapshot.owner_user_id, - profile_id: snapshot.profile_id, - world_type: snapshot.world_type, - world_name: snapshot.world_name, - subtitle: snapshot.subtitle, - summary_text: snapshot.summary_text, - cover_image_src: snapshot.cover_image_src, - saved_at_micros: snapshot.saved_at_micros, - bottom_tab: snapshot.bottom_tab, - game_state_json: snapshot.game_state_json, - current_story_json: snapshot.current_story_json, - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_custom_world_library_entry_from_profile_snapshot( - snapshot: BindingCustomWorldProfileSnapshot, -) -> Result { - let profile = serde_json::from_str::(&snapshot.profile_payload_json) - .map_err(|error| { - SpacetimeClientError::Runtime(format!( - "custom world profile payload JSON 非法: {error}" - )) - })?; - - Ok(CustomWorldLibraryEntryRecord { - owner_user_id: snapshot.owner_user_id, - profile_id: snapshot.profile_id, - public_work_code: snapshot.public_work_code, - author_public_user_code: snapshot.author_public_user_code, - profile, - visibility: map_custom_world_publication_status(snapshot.publication_status).to_string(), - published_at: snapshot.published_at_micros.map(format_timestamp_micros), - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - author_display_name: snapshot.author_display_name, - world_name: snapshot.world_name, - subtitle: snapshot.subtitle, - summary_text: snapshot.summary_text, - cover_image_src: snapshot.cover_image_src, - theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( - snapshot.theme_mode, - )) - .to_string(), - playable_npc_count: snapshot.playable_npc_count, - landmark_count: snapshot.landmark_count, - }) -} - -fn map_custom_world_gallery_entry_snapshot( - snapshot: BindingCustomWorldGalleryEntrySnapshot, -) -> Result { - Ok(CustomWorldGalleryEntryRecord { - owner_user_id: snapshot.owner_user_id, - profile_id: snapshot.profile_id, - public_work_code: snapshot.public_work_code, - author_public_user_code: snapshot.author_public_user_code, - visibility: "published".to_string(), - published_at: Some(format_timestamp_micros(snapshot.published_at_micros)), - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - author_display_name: snapshot.author_display_name, - world_name: snapshot.world_name, - subtitle: snapshot.subtitle, - summary_text: snapshot.summary_text, - cover_image_src: snapshot.cover_image_src, - theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( - snapshot.theme_mode, - )) - .to_string(), - playable_npc_count: snapshot.playable_npc_count, - landmark_count: snapshot.landmark_count, - }) -} - -fn map_custom_world_published_profile_compile_snapshot( - snapshot: BindingCustomWorldPublishedProfileCompileSnapshot, -) -> Result { - let compiled_profile = - serde_json::from_str::(&snapshot.compiled_profile_payload_json) - .map_err(|error| { - SpacetimeClientError::Runtime(format!( - "published profile compile JSON 非法: {error}" - )) - })?; - - Ok(CustomWorldPublishedProfileCompileRecord { - profile_id: snapshot.profile_id, - owner_user_id: snapshot.owner_user_id, - world_name: snapshot.world_name, - subtitle: snapshot.subtitle, - summary_text: snapshot.summary_text, - theme_mode: format_custom_world_theme_mode(map_custom_world_theme_mode_back( - snapshot.theme_mode, - )) - .to_string(), - cover_image_src: snapshot.cover_image_src, - playable_npc_count: snapshot.playable_npc_count, - landmark_count: snapshot.landmark_count, - author_display_name: snapshot.author_display_name, - compiled_profile: compiled_profile, - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - }) -} - -fn map_custom_world_work_summary_snapshot( - snapshot: BindingCustomWorldWorkSummarySnapshot, -) -> Result { - Ok(CustomWorldWorkSummaryRecord { - work_id: snapshot.work_id, - source_type: snapshot.source_type, - status: snapshot.status, - title: snapshot.title, - subtitle: snapshot.subtitle, - summary: snapshot.summary, - cover_image_src: snapshot.cover_image_src, - cover_render_mode: snapshot.cover_render_mode, - cover_character_image_srcs: parse_json_string_array( - &snapshot.cover_character_image_srcs_json, - "custom world work cover_character_image_srcs_json", - )?, - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - published_at: snapshot.published_at_micros.map(format_timestamp_micros), - stage: snapshot.stage.map(map_rpg_agent_stage), - stage_label: snapshot.stage_label, - playable_npc_count: snapshot.playable_npc_count, - landmark_count: snapshot.landmark_count, - role_visual_ready_count: snapshot.role_visual_ready_count, - role_animation_ready_count: snapshot.role_animation_ready_count, - role_asset_summary_label: snapshot.role_asset_summary_label, - session_id: snapshot.session_id, - profile_id: snapshot.profile_id, - can_resume: snapshot.can_resume, - can_enter_world: snapshot.can_enter_world, - blocker_count: snapshot.blocker_count, - publish_ready: snapshot.publish_ready, - }) -} - -fn map_custom_world_agent_session_snapshot( - snapshot: BindingCustomWorldAgentSessionSnapshot, -) -> Result { - let anchor_content = parse_json_value( - &snapshot.anchor_content_json, - "custom world agent anchor_content_json", - )?; - let creator_intent = parse_optional_json_value( - snapshot.creator_intent_json.as_deref(), - serde_json::json!({}), - "custom world agent creator_intent_json", - )?; - let creator_intent_readiness = parse_json_value( - &snapshot.creator_intent_readiness_json, - "custom world agent creator_intent_readiness_json", - )?; - let anchor_pack = parse_optional_json_value( - snapshot.anchor_pack_json.as_deref(), - serde_json::json!({}), - "custom world agent anchor_pack_json", - )?; - let lock_state = parse_optional_json_value( - snapshot.lock_state_json.as_deref(), - serde_json::json!({}), - "custom world agent lock_state_json", - )?; - let draft_profile = parse_optional_json_value( - snapshot.draft_profile_json.as_deref(), - serde_json::json!({}), - "custom world agent draft_profile_json", - )?; - let pending_clarifications = parse_json_array( - &snapshot.pending_clarifications_json, - "custom world agent pending_clarifications_json", - )?; - let suggested_actions = parse_json_array( - &snapshot.suggested_actions_json, - "custom world agent suggested_actions_json", - )?; - let recommended_replies = parse_json_string_array( - &snapshot.recommended_replies_json, - "custom world agent recommended_replies_json", - )?; - let quality_findings = parse_json_array( - &snapshot.quality_findings_json, - "custom world agent quality_findings_json", - )?; - let asset_coverage = parse_json_value( - &snapshot.asset_coverage_json, - "custom world agent asset_coverage_json", - )?; - let checkpoints_json = parse_json_array( - &snapshot.checkpoints_json, - "custom world agent checkpoints_json", - )?; - let checkpoints = checkpoints_json - .into_iter() - .map(map_custom_world_checkpoint_record) - .collect::, _>>()?; - let supported_actions = parse_supported_actions_json(&snapshot.supported_actions_json)?; - let publish_gate = snapshot - .publish_gate_json - .as_deref() - .map(parse_custom_world_publish_gate_record) - .transpose()?; - - Ok(CustomWorldAgentSessionRecord { - session_id: snapshot.session_id, - seed_text: snapshot.seed_text, - current_turn: snapshot.current_turn, - anchor_content, - progress_percent: snapshot.progress_percent, - last_assistant_reply: snapshot.last_assistant_reply, - stage: map_rpg_agent_stage(snapshot.stage), - focus_card_id: snapshot.focus_card_id, - creator_intent, - creator_intent_readiness, - anchor_pack, - lock_state, - draft_profile, - messages: snapshot - .messages - .into_iter() - .map(map_custom_world_agent_message_snapshot) - .collect(), - draft_cards: snapshot - .draft_cards - .into_iter() - .map(map_custom_world_draft_card_snapshot) - .collect::, _>>()?, - pending_clarifications, - suggested_actions, - recommended_replies, - quality_findings, - asset_coverage, - checkpoints, - supported_actions, - publish_gate, - result_preview: snapshot - .result_preview_json - .as_deref() - .map(|value| parse_json_value(value, "custom world agent result_preview_json")) - .transpose()?, - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - }) -} - -fn map_custom_world_agent_message_snapshot( - snapshot: BindingCustomWorldAgentMessageSnapshot, -) -> CustomWorldAgentMessageRecord { - CustomWorldAgentMessageRecord { - message_id: snapshot.message_id, - role: format_rpg_agent_message_role(snapshot.role).to_string(), - kind: format_rpg_agent_message_kind(snapshot.kind).to_string(), - text: snapshot.text, - created_at: format_timestamp_micros(snapshot.created_at_micros), - related_operation_id: snapshot.related_operation_id, - } -} - -fn map_custom_world_agent_operation_snapshot( - snapshot: BindingCustomWorldAgentOperationSnapshot, -) -> CustomWorldAgentOperationRecord { - CustomWorldAgentOperationRecord { - operation_id: snapshot.operation_id, - operation_type: format_rpg_agent_operation_type(snapshot.operation_type).to_string(), - status: format_rpg_agent_operation_status(snapshot.status).to_string(), - phase_label: snapshot.phase_label, - phase_detail: snapshot.phase_detail, - progress: snapshot.progress, - error_message: snapshot.error_message, - } -} - -fn map_custom_world_draft_card_snapshot( - snapshot: BindingCustomWorldDraftCardSnapshot, -) -> Result { - Ok(CustomWorldDraftCardRecord { - card_id: snapshot.card_id, - kind: format_rpg_agent_draft_card_kind(snapshot.kind).to_string(), - title: snapshot.title, - subtitle: snapshot.subtitle, - summary: snapshot.summary, - status: format_rpg_agent_draft_card_status(snapshot.status).to_string(), - linked_ids: parse_json_string_array( - &snapshot.linked_ids_json, - "custom world draft_card linked_ids_json", - )?, - warning_count: snapshot.warning_count, - asset_status: snapshot - .asset_status - .map(format_custom_world_role_asset_status_back), - asset_status_label: snapshot.asset_status_label, - detail_payload: snapshot - .detail_payload_json - .as_deref() - .map(|value| parse_json_value(value, "custom world draft_card detail_payload_json")) - .transpose()?, - }) -} - -fn map_custom_world_draft_card_detail_snapshot( - snapshot: BindingCustomWorldDraftCardDetailSnapshot, -) -> Result { - Ok(CustomWorldDraftCardDetailRecord { - card_id: snapshot.card_id, - kind: format_rpg_agent_draft_card_kind(snapshot.kind).to_string(), - title: snapshot.title, - sections: snapshot - .sections - .into_iter() - .map(map_custom_world_draft_card_detail_section_snapshot) - .collect(), - linked_ids: parse_json_string_array( - &snapshot.linked_ids_json, - "custom world card detail linked_ids_json", - )?, - locked: snapshot.locked, - editable: snapshot.editable, - editable_section_ids: parse_json_string_array( - &snapshot.editable_section_ids_json, - "custom world card detail editable_section_ids_json", - )?, - warning_messages: parse_json_string_array( - &snapshot.warning_messages_json, - "custom world card detail warning_messages_json", - )?, - asset_status: snapshot - .asset_status - .map(format_custom_world_role_asset_status_back), - asset_status_label: snapshot.asset_status_label, - }) -} - -fn map_custom_world_draft_card_detail_section_snapshot( - snapshot: BindingCustomWorldDraftCardDetailSectionSnapshot, -) -> CustomWorldDraftCardDetailSectionRecord { - CustomWorldDraftCardDetailSectionRecord { - section_id: snapshot.section_id, - label: snapshot.label, - value: snapshot.value, - } -} - -fn map_big_fish_session_snapshot(snapshot: BindingBigFishSessionSnapshot) -> BigFishSessionRecord { - BigFishSessionRecord { - session_id: snapshot.session_id, - current_turn: snapshot.current_turn, - progress_percent: snapshot.progress_percent, - stage: format_big_fish_creation_stage(snapshot.stage).to_string(), - anchor_pack: map_big_fish_anchor_pack(snapshot.anchor_pack), - draft: snapshot.draft.map(map_big_fish_game_draft), - asset_slots: snapshot - .asset_slots - .into_iter() - .map(map_big_fish_asset_slot_snapshot) - .collect(), - asset_coverage: map_big_fish_asset_coverage(snapshot.asset_coverage), - messages: snapshot - .messages - .into_iter() - .map(map_big_fish_agent_message_snapshot) - .collect(), - last_assistant_reply: snapshot.last_assistant_reply, - publish_ready: snapshot.publish_ready, - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - } -} - -fn map_puzzle_agent_session_snapshot( - snapshot: DomainPuzzleAgentSessionSnapshot, -) -> PuzzleAgentSessionRecord { - PuzzleAgentSessionRecord { - session_id: snapshot.session_id, - current_turn: snapshot.current_turn, - progress_percent: snapshot.progress_percent, - stage: snapshot.stage.as_str().to_string(), - anchor_pack: map_puzzle_anchor_pack(snapshot.anchor_pack), - draft: snapshot.draft.map(map_puzzle_result_draft), - messages: snapshot - .messages - .into_iter() - .map(map_puzzle_agent_message_snapshot) - .collect(), - last_assistant_reply: snapshot.last_assistant_reply, - published_profile_id: snapshot.published_profile_id, - suggested_actions: snapshot - .suggested_actions - .into_iter() - .map(map_puzzle_suggested_action) - .collect(), - result_preview: snapshot.result_preview.map(map_puzzle_result_preview), - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - } -} - -fn map_puzzle_anchor_pack(snapshot: DomainPuzzleAnchorPack) -> PuzzleAnchorPackRecord { - PuzzleAnchorPackRecord { - theme_promise: map_puzzle_anchor_item(snapshot.theme_promise), - visual_subject: map_puzzle_anchor_item(snapshot.visual_subject), - visual_mood: map_puzzle_anchor_item(snapshot.visual_mood), - composition_hooks: map_puzzle_anchor_item(snapshot.composition_hooks), - tags_and_forbidden: map_puzzle_anchor_item(snapshot.tags_and_forbidden), - } -} - -fn map_puzzle_anchor_item(snapshot: DomainPuzzleAnchorItem) -> PuzzleAnchorItemRecord { - PuzzleAnchorItemRecord { - key: snapshot.key, - label: snapshot.label, - value: snapshot.value, - status: snapshot.status.as_str().to_string(), - } -} - -fn map_puzzle_result_draft(snapshot: DomainPuzzleResultDraft) -> PuzzleResultDraftRecord { - PuzzleResultDraftRecord { - level_name: snapshot.level_name, - summary: snapshot.summary, - theme_tags: snapshot.theme_tags, - forbidden_directives: snapshot.forbidden_directives, - creator_intent: snapshot.creator_intent.map(map_puzzle_creator_intent), - anchor_pack: map_puzzle_anchor_pack(snapshot.anchor_pack), - candidates: snapshot - .candidates - .into_iter() - .map(map_puzzle_generated_image_candidate) - .collect(), - selected_candidate_id: snapshot.selected_candidate_id, - cover_image_src: snapshot.cover_image_src, - cover_asset_id: snapshot.cover_asset_id, - generation_status: snapshot.generation_status, - } -} - -fn map_puzzle_creator_intent(snapshot: DomainPuzzleCreatorIntent) -> PuzzleCreatorIntentRecord { - PuzzleCreatorIntentRecord { - source_mode: snapshot.source_mode, - raw_messages_summary: snapshot.raw_messages_summary, - theme_promise: snapshot.theme_promise, - visual_subject: snapshot.visual_subject, - visual_mood: snapshot.visual_mood, - composition_hooks: snapshot.composition_hooks, - theme_tags: snapshot.theme_tags, - forbidden_directives: snapshot.forbidden_directives, - } -} - -fn map_puzzle_generated_image_candidate( - snapshot: DomainPuzzleGeneratedImageCandidate, -) -> PuzzleGeneratedImageCandidateRecord { - PuzzleGeneratedImageCandidateRecord { - candidate_id: snapshot.candidate_id, - image_src: snapshot.image_src, - asset_id: snapshot.asset_id, - prompt: snapshot.prompt, - actual_prompt: snapshot.actual_prompt, - source_type: snapshot.source_type, - selected: snapshot.selected, - } -} - -fn map_puzzle_agent_message_snapshot( - snapshot: DomainPuzzleAgentMessageSnapshot, -) -> PuzzleAgentMessageRecord { - PuzzleAgentMessageRecord { - message_id: snapshot.message_id, - role: snapshot.role.as_str().to_string(), - kind: snapshot.kind.as_str().to_string(), - text: snapshot.text, - created_at: format_timestamp_micros(snapshot.created_at_micros), - } -} - -fn map_puzzle_suggested_action( - snapshot: DomainPuzzleAgentSuggestedAction, -) -> PuzzleAgentSuggestedActionRecord { - PuzzleAgentSuggestedActionRecord { - action_id: snapshot.id, - action_type: snapshot.action_type, - label: snapshot.label, - } -} - -fn map_puzzle_result_preview( - snapshot: DomainPuzzleResultPreviewEnvelope, -) -> PuzzleResultPreviewRecord { - PuzzleResultPreviewRecord { - draft: map_puzzle_result_draft(snapshot.draft), - blockers: snapshot - .blockers - .into_iter() - .map(map_puzzle_result_preview_blocker) - .collect(), - quality_findings: snapshot - .quality_findings - .into_iter() - .map(map_puzzle_result_preview_finding) - .collect(), - publish_ready: snapshot.publish_ready, - } -} - -fn map_puzzle_result_preview_blocker( - snapshot: DomainPuzzleResultPreviewBlocker, -) -> PuzzleResultPreviewBlockerRecord { - PuzzleResultPreviewBlockerRecord { - blocker_id: snapshot.id, - code: snapshot.code, - message: snapshot.message, - } -} - -fn map_puzzle_result_preview_finding( - snapshot: DomainPuzzleResultPreviewFinding, -) -> PuzzleResultPreviewFindingRecord { - PuzzleResultPreviewFindingRecord { - finding_id: snapshot.id, - severity: snapshot.severity, - code: snapshot.code, - message: snapshot.message, - } -} - -fn map_puzzle_work_profile(snapshot: DomainPuzzleWorkProfile) -> PuzzleWorkProfileRecord { - PuzzleWorkProfileRecord { - work_id: snapshot.work_id, - profile_id: snapshot.profile_id, - owner_user_id: snapshot.owner_user_id, - source_session_id: snapshot.source_session_id, - author_display_name: snapshot.author_display_name, - level_name: snapshot.level_name, - summary: snapshot.summary, - theme_tags: snapshot.theme_tags, - cover_image_src: snapshot.cover_image_src, - cover_asset_id: snapshot.cover_asset_id, - publication_status: snapshot.publication_status.as_str().to_string(), - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - published_at: snapshot.published_at_micros.map(format_timestamp_micros), - play_count: snapshot.play_count, - publish_ready: snapshot.publish_ready, - anchor_pack: map_puzzle_anchor_pack(snapshot.anchor_pack), - } -} - -fn map_puzzle_run_snapshot(snapshot: DomainPuzzleRunSnapshot) -> PuzzleRunRecord { - PuzzleRunRecord { - run_id: snapshot.run_id, - entry_profile_id: snapshot.entry_profile_id, - cleared_level_count: snapshot.cleared_level_count, - current_level_index: snapshot.current_level_index, - current_grid_size: snapshot.current_grid_size, - played_profile_ids: snapshot.played_profile_ids, - previous_level_tags: snapshot.previous_level_tags, - current_level: snapshot - .current_level - .map(map_puzzle_runtime_level_snapshot), - recommended_next_profile_id: snapshot.recommended_next_profile_id, - } -} - -fn map_puzzle_runtime_level_snapshot( - snapshot: DomainPuzzleRuntimeLevelSnapshot, -) -> PuzzleRuntimeLevelRecord { - PuzzleRuntimeLevelRecord { - run_id: snapshot.run_id, - level_index: snapshot.level_index, - grid_size: snapshot.grid_size, - profile_id: snapshot.profile_id, - level_name: snapshot.level_name, - author_display_name: snapshot.author_display_name, - theme_tags: snapshot.theme_tags, - cover_image_src: snapshot.cover_image_src, - board: map_puzzle_board_snapshot(snapshot.board), - status: snapshot.status.as_str().to_string(), - } -} - -fn map_puzzle_board_snapshot(snapshot: DomainPuzzleBoardSnapshot) -> PuzzleBoardRecord { - PuzzleBoardRecord { - rows: snapshot.rows, - cols: snapshot.cols, - pieces: snapshot - .pieces - .into_iter() - .map(map_puzzle_piece_state) - .collect(), - merged_groups: snapshot - .merged_groups - .into_iter() - .map(map_puzzle_merged_group_state) - .collect(), - selected_piece_id: snapshot.selected_piece_id, - all_tiles_resolved: snapshot.all_tiles_resolved, - } -} - -fn map_puzzle_piece_state(snapshot: DomainPuzzlePieceState) -> PuzzlePieceStateRecord { - PuzzlePieceStateRecord { - piece_id: snapshot.piece_id, - correct_row: snapshot.correct_row, - correct_col: snapshot.correct_col, - current_row: snapshot.current_row, - current_col: snapshot.current_col, - merged_group_id: snapshot.merged_group_id, - } -} - -fn map_puzzle_merged_group_state( - snapshot: DomainPuzzleMergedGroupState, -) -> PuzzleMergedGroupRecord { - PuzzleMergedGroupRecord { - group_id: snapshot.group_id, - piece_ids: snapshot.piece_ids, - occupied_cells: snapshot - .occupied_cells - .into_iter() - .map(map_puzzle_cell_position) - .collect(), - } -} - -fn map_puzzle_cell_position(snapshot: DomainPuzzleCellPosition) -> PuzzleCellPositionRecord { - PuzzleCellPositionRecord { - row: snapshot.row, - col: snapshot.col, - } -} - -fn map_big_fish_anchor_pack(snapshot: BindingBigFishAnchorPack) -> BigFishAnchorPackRecord { - BigFishAnchorPackRecord { - gameplay_promise: map_big_fish_anchor_item(snapshot.gameplay_promise), - ecology_visual_theme: map_big_fish_anchor_item(snapshot.ecology_visual_theme), - growth_ladder: map_big_fish_anchor_item(snapshot.growth_ladder), - risk_tempo: map_big_fish_anchor_item(snapshot.risk_tempo), - } -} - -fn map_big_fish_anchor_item(snapshot: BindingBigFishAnchorItem) -> BigFishAnchorItemRecord { - BigFishAnchorItemRecord { - key: snapshot.key, - label: snapshot.label, - value: snapshot.value, - status: format_big_fish_anchor_status(snapshot.status).to_string(), - } -} - -fn map_big_fish_game_draft(snapshot: BindingBigFishGameDraft) -> BigFishGameDraftRecord { - BigFishGameDraftRecord { - title: snapshot.title, - subtitle: snapshot.subtitle, - core_fun: snapshot.core_fun, - ecology_theme: snapshot.ecology_theme, - levels: snapshot - .levels - .into_iter() - .map(map_big_fish_level_blueprint) - .collect(), - background: map_big_fish_background_blueprint(snapshot.background), - runtime_params: map_big_fish_runtime_params(snapshot.runtime_params), - } -} - -fn map_big_fish_level_blueprint( - snapshot: BindingBigFishLevelBlueprint, -) -> BigFishLevelBlueprintRecord { - BigFishLevelBlueprintRecord { - level: snapshot.level, - name: snapshot.name, - one_line_fantasy: snapshot.one_line_fantasy, - silhouette_direction: snapshot.silhouette_direction, - size_ratio: snapshot.size_ratio, - visual_prompt_seed: snapshot.visual_prompt_seed, - motion_prompt_seed: snapshot.motion_prompt_seed, - merge_source_level: snapshot.merge_source_level, - prey_window: snapshot.prey_window, - threat_window: snapshot.threat_window, - is_final_level: snapshot.is_final_level, - } -} - -fn map_big_fish_background_blueprint( - snapshot: BindingBigFishBackgroundBlueprint, -) -> BigFishBackgroundBlueprintRecord { - BigFishBackgroundBlueprintRecord { - theme: snapshot.theme, - color_mood: snapshot.color_mood, - foreground_hints: snapshot.foreground_hints, - midground_composition: snapshot.midground_composition, - background_depth: snapshot.background_depth, - safe_play_area_hint: snapshot.safe_play_area_hint, - spawn_edge_hint: snapshot.spawn_edge_hint, - background_prompt_seed: snapshot.background_prompt_seed, - } -} - -fn map_big_fish_runtime_params( - snapshot: BindingBigFishRuntimeParams, -) -> BigFishRuntimeParamsRecord { - BigFishRuntimeParamsRecord { - level_count: snapshot.level_count, - merge_count_per_upgrade: snapshot.merge_count_per_upgrade, - spawn_target_count: snapshot.spawn_target_count, - leader_move_speed: snapshot.leader_move_speed, - follower_catch_up_speed: snapshot.follower_catch_up_speed, - offscreen_cull_seconds: snapshot.offscreen_cull_seconds, - prey_spawn_delta_levels: snapshot.prey_spawn_delta_levels, - threat_spawn_delta_levels: snapshot.threat_spawn_delta_levels, - win_level: snapshot.win_level, - } -} - -fn map_big_fish_asset_slot_snapshot( - snapshot: BindingBigFishAssetSlotSnapshot, -) -> BigFishAssetSlotRecord { - BigFishAssetSlotRecord { - slot_id: snapshot.slot_id, - asset_kind: format_big_fish_asset_kind(snapshot.asset_kind).to_string(), - level: snapshot.level, - motion_key: snapshot.motion_key, - status: format_big_fish_asset_status(snapshot.status).to_string(), - asset_url: snapshot.asset_url, - prompt_snapshot: snapshot.prompt_snapshot, - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - } -} - -fn map_big_fish_asset_coverage( - snapshot: BindingBigFishAssetCoverage, -) -> BigFishAssetCoverageRecord { - BigFishAssetCoverageRecord { - level_main_image_ready_count: snapshot.level_main_image_ready_count, - level_motion_ready_count: snapshot.level_motion_ready_count, - background_ready: snapshot.background_ready, - required_level_count: snapshot.required_level_count, - publish_ready: snapshot.publish_ready, - blockers: snapshot.blockers, - } -} - -fn map_big_fish_agent_message_snapshot( - snapshot: BindingBigFishAgentMessageSnapshot, -) -> BigFishAgentMessageRecord { - BigFishAgentMessageRecord { - message_id: snapshot.message_id, - role: format_big_fish_agent_message_role(snapshot.role).to_string(), - kind: format_big_fish_agent_message_kind(snapshot.kind).to_string(), - text: snapshot.text, - created_at: format_timestamp_micros(snapshot.created_at_micros), - } -} - -fn map_big_fish_runtime_snapshot(snapshot: BindingBigFishRuntimeSnapshot) -> BigFishRuntimeRecord { - BigFishRuntimeRecord { - run_id: snapshot.run_id, - session_id: snapshot.session_id, - status: format_big_fish_run_status(snapshot.status).to_string(), - tick: snapshot.tick, - player_level: snapshot.player_level, - win_level: snapshot.win_level, - leader_entity_id: snapshot.leader_entity_id, - owned_entities: snapshot - .owned_entities - .into_iter() - .map(map_big_fish_runtime_entity) - .collect(), - wild_entities: snapshot - .wild_entities - .into_iter() - .map(map_big_fish_runtime_entity) - .collect(), - camera_center: map_big_fish_vector2(snapshot.camera_center), - last_input: map_big_fish_vector2(snapshot.last_input), - event_log: snapshot.event_log, - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - } -} - -fn map_big_fish_runtime_entity( - snapshot: BindingBigFishRuntimeEntity, -) -> BigFishRuntimeEntityRecord { - BigFishRuntimeEntityRecord { - entity_id: snapshot.entity_id, - level: snapshot.level, - position: map_big_fish_vector2(snapshot.position), - radius: snapshot.radius, - offscreen_seconds: snapshot.offscreen_seconds, - } -} - -fn map_big_fish_vector2(snapshot: BindingBigFishVector2) -> BigFishVector2Record { - BigFishVector2Record { - x: snapshot.x, - y: snapshot.y, - } -} - -fn map_story_session_snapshot(snapshot: BindingStorySessionSnapshot) -> StorySessionRecord { - StorySessionRecord { - story_session_id: snapshot.story_session_id, - runtime_session_id: snapshot.runtime_session_id, - actor_user_id: snapshot.actor_user_id, - world_profile_id: snapshot.world_profile_id, - initial_prompt: snapshot.initial_prompt, - opening_summary: snapshot.opening_summary, - latest_narrative_text: snapshot.latest_narrative_text, - latest_choice_function_id: snapshot.latest_choice_function_id, - status: map_story_session_status(snapshot.status) - .as_str() - .to_string(), - version: snapshot.version, - created_at: format_timestamp_micros(snapshot.created_at_micros), - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - } -} - -fn map_ai_task_snapshot(snapshot: BindingAiTaskSnapshot) -> AiTaskRecord { - AiTaskRecord { - task_id: snapshot.task_id, - task_kind: format_ai_task_kind(snapshot.task_kind).to_string(), - owner_user_id: snapshot.owner_user_id, - request_label: snapshot.request_label, - source_module: snapshot.source_module, - source_entity_id: snapshot.source_entity_id, - request_payload_json: snapshot.request_payload_json, - status: format_ai_task_status(snapshot.status).to_string(), - failure_message: snapshot.failure_message, - stages: snapshot - .stages - .into_iter() - .map(map_ai_task_stage_snapshot) - .collect(), - result_references: snapshot - .result_references - .into_iter() - .map(map_ai_result_reference_snapshot) - .collect(), - latest_text_output: snapshot.latest_text_output, - latest_structured_payload_json: snapshot.latest_structured_payload_json, - version: snapshot.version, - created_at: format_timestamp_micros(snapshot.created_at_micros), - started_at: snapshot.started_at_micros.map(format_timestamp_micros), - completed_at: snapshot.completed_at_micros.map(format_timestamp_micros), - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - } -} - -fn map_ai_task_stage_snapshot(snapshot: BindingAiTaskStageSnapshot) -> AiTaskStageRecord { - AiTaskStageRecord { - stage_kind: format_ai_task_stage_kind(snapshot.stage_kind).to_string(), - label: snapshot.label, - detail: snapshot.detail, - order: snapshot.order, - status: format_ai_task_stage_status(snapshot.status).to_string(), - text_output: snapshot.text_output, - structured_payload_json: snapshot.structured_payload_json, - warning_messages: snapshot.warning_messages, - started_at: snapshot.started_at_micros.map(format_timestamp_micros), - completed_at: snapshot.completed_at_micros.map(format_timestamp_micros), - } -} - -fn map_ai_text_chunk_snapshot(snapshot: BindingAiTextChunkSnapshot) -> AiTextChunkRecord { - AiTextChunkRecord { - chunk_id: snapshot.chunk_id, - task_id: snapshot.task_id, - stage_kind: format_ai_task_stage_kind(snapshot.stage_kind).to_string(), - sequence: snapshot.sequence, - delta_text: snapshot.delta_text, - created_at: format_timestamp_micros(snapshot.created_at_micros), - } -} - -fn map_ai_result_reference_snapshot( - snapshot: BindingAiResultReferenceSnapshot, -) -> AiResultReferenceRecord { - AiResultReferenceRecord { - result_ref_id: snapshot.result_ref_id, - task_id: snapshot.task_id, - reference_kind: format_ai_result_reference_kind(snapshot.reference_kind).to_string(), - reference_id: snapshot.reference_id, - label: snapshot.label, - created_at: format_timestamp_micros(snapshot.created_at_micros), - } -} - -fn map_story_event_snapshot(snapshot: BindingStoryEventSnapshot) -> StoryEventRecord { - StoryEventRecord { - event_id: snapshot.event_id, - story_session_id: snapshot.story_session_id, - event_kind: map_story_event_kind(snapshot.event_kind) - .as_str() - .to_string(), - narrative_text: snapshot.narrative_text, - choice_function_id: snapshot.choice_function_id, - created_at: format_timestamp_micros(snapshot.created_at_micros), - } -} - -fn map_battle_state_snapshot(snapshot: BindingBattleStateSnapshot) -> DomainBattleStateSnapshot { - DomainBattleStateSnapshot { - battle_state_id: snapshot.battle_state_id, - story_session_id: snapshot.story_session_id, - runtime_session_id: snapshot.runtime_session_id, - actor_user_id: snapshot.actor_user_id, - chapter_id: snapshot.chapter_id, - target_npc_id: snapshot.target_npc_id, - target_name: snapshot.target_name, - battle_mode: map_battle_mode_back(snapshot.battle_mode), - status: map_battle_status(snapshot.status), - player_hp: snapshot.player_hp, - player_max_hp: snapshot.player_max_hp, - player_mana: snapshot.player_mana, - player_max_mana: snapshot.player_max_mana, - target_hp: snapshot.target_hp, - target_max_hp: snapshot.target_max_hp, - experience_reward: snapshot.experience_reward, - reward_items: snapshot - .reward_items - .into_iter() - .map(map_runtime_item_reward_item_snapshot_back) - .collect(), - turn_index: snapshot.turn_index, - last_action_function_id: snapshot.last_action_function_id, - last_action_text: snapshot.last_action_text, - last_result_text: snapshot.last_result_text, - last_damage_dealt: snapshot.last_damage_dealt, - last_damage_taken: snapshot.last_damage_taken, - last_outcome: map_combat_outcome(snapshot.last_outcome), - version: snapshot.version, - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_runtime_inventory_state_snapshot( - snapshot: BindingRuntimeInventoryStateSnapshot, -) -> DomainRuntimeInventoryStateSnapshot { - DomainRuntimeInventoryStateSnapshot { - runtime_session_id: snapshot.runtime_session_id, - actor_user_id: snapshot.actor_user_id, - backpack_items: snapshot - .backpack_items - .into_iter() - .map(map_inventory_slot_snapshot) - .collect(), - equipment_items: snapshot - .equipment_items - .into_iter() - .map(map_inventory_slot_snapshot) - .collect(), - } -} - -fn map_resolve_combat_action_result( - result: BindingResolveCombatActionResult, -) -> DomainResolveCombatActionResult { - DomainResolveCombatActionResult { - snapshot: map_battle_state_snapshot(result.snapshot), - damage_dealt: result.damage_dealt, - damage_taken: result.damage_taken, - outcome: map_combat_outcome(result.outcome), - } -} - -fn map_npc_battle_interaction_result( - result: BindingNpcBattleInteractionResult, -) -> NpcBattleInteractionSnapshot { - NpcBattleInteractionSnapshot { - interaction: map_npc_interaction_result(result.interaction), - battle_state: map_battle_state_snapshot(result.battle_state), - } -} - -fn map_inventory_slot_snapshot( - snapshot: BindingInventorySlotSnapshot, -) -> module_inventory::InventorySlotSnapshot { - module_inventory::InventorySlotSnapshot { - slot_id: snapshot.slot_id, - runtime_session_id: snapshot.runtime_session_id, - story_session_id: snapshot.story_session_id, - actor_user_id: snapshot.actor_user_id, - container_kind: map_inventory_container_kind(snapshot.container_kind), - slot_key: snapshot.slot_key, - item_id: snapshot.item_id, - category: snapshot.category, - name: snapshot.name, - description: snapshot.description, - quantity: snapshot.quantity, - rarity: map_inventory_item_rarity(snapshot.rarity), - tags: snapshot.tags, - stackable: snapshot.stackable, - stack_key: snapshot.stack_key, - equipment_slot_id: snapshot.equipment_slot_id.map(map_inventory_equipment_slot), - source_kind: map_inventory_item_source_kind(snapshot.source_kind), - source_reference_id: snapshot.source_reference_id, - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_npc_interaction_result(result: BindingNpcInteractionResult) -> DomainNpcInteractionResult { - DomainNpcInteractionResult { - npc_state: map_npc_state_snapshot(result.npc_state), - interaction_status: map_npc_interaction_status(result.interaction_status), - action_text: result.action_text, - result_text: result.result_text, - story_text: result.story_text, - battle_mode: result.battle_mode.map(map_npc_interaction_battle_mode), - encounter_closed: result.encounter_closed, - affinity_changed: result.affinity_changed, - previous_affinity: result.previous_affinity, - next_affinity: result.next_affinity, - } -} - -fn map_npc_state_snapshot(snapshot: BindingNpcStateSnapshot) -> DomainNpcStateSnapshot { - DomainNpcStateSnapshot { - npc_state_id: snapshot.npc_state_id, - runtime_session_id: snapshot.runtime_session_id, - npc_id: snapshot.npc_id, - npc_name: snapshot.npc_name, - affinity: snapshot.affinity, - relation_state: map_npc_relation_state(snapshot.relation_state), - help_used: snapshot.help_used, - chatted_count: snapshot.chatted_count, - gifts_given: snapshot.gifts_given, - recruited: snapshot.recruited, - trade_stock_signature: snapshot.trade_stock_signature, - revealed_facts: snapshot.revealed_facts, - known_attribute_rumors: snapshot.known_attribute_rumors, - first_meaningful_contact_resolved: snapshot.first_meaningful_contact_resolved, - seen_backstory_chapter_ids: snapshot.seen_backstory_chapter_ids, - stance_profile: map_npc_stance_profile(snapshot.stance_profile), - created_at_micros: snapshot.created_at_micros, - updated_at_micros: snapshot.updated_at_micros, - } -} - -fn map_npc_relation_state(value: BindingNpcRelationState) -> DomainNpcRelationState { - DomainNpcRelationState { - affinity: value.affinity, - stance: map_npc_relation_stance(value.stance), - } -} - -fn map_npc_stance_profile(value: BindingNpcStanceProfile) -> DomainNpcStanceProfile { - DomainNpcStanceProfile { - trust: value.trust, - warmth: value.warmth, - ideological_fit: value.ideological_fit, - fear_or_guard: value.fear_or_guard, - loyalty: value.loyalty, - current_conflict_tag: value.current_conflict_tag, - recent_approvals: value.recent_approvals, - recent_disapprovals: value.recent_disapprovals, - } -} - -fn map_npc_interaction_status(value: BindingNpcInteractionStatus) -> DomainNpcInteractionStatus { - match value { - BindingNpcInteractionStatus::Previewed => DomainNpcInteractionStatus::Previewed, - BindingNpcInteractionStatus::Dialogue => DomainNpcInteractionStatus::Dialogue, - BindingNpcInteractionStatus::Resolved => DomainNpcInteractionStatus::Resolved, - BindingNpcInteractionStatus::Recruited => DomainNpcInteractionStatus::Recruited, - BindingNpcInteractionStatus::BattlePending => DomainNpcInteractionStatus::BattlePending, - BindingNpcInteractionStatus::Left => DomainNpcInteractionStatus::Left, - } -} - -fn map_npc_interaction_battle_mode( - value: BindingNpcInteractionBattleMode, -) -> DomainNpcInteractionBattleMode { - match value { - BindingNpcInteractionBattleMode::Fight => DomainNpcInteractionBattleMode::Fight, - BindingNpcInteractionBattleMode::Spar => DomainNpcInteractionBattleMode::Spar, - } -} - -fn map_npc_relation_stance(value: BindingNpcRelationStance) -> DomainNpcRelationStance { - match value { - BindingNpcRelationStance::Hostile => DomainNpcRelationStance::Hostile, - BindingNpcRelationStance::Guarded => DomainNpcRelationStance::Guarded, - BindingNpcRelationStance::Neutral => DomainNpcRelationStance::Neutral, - BindingNpcRelationStance::Cooperative => DomainNpcRelationStance::Cooperative, - BindingNpcRelationStance::Bonded => DomainNpcRelationStance::Bonded, - } -} - -fn map_access_policy( - value: AssetObjectAccessPolicy, -) -> crate::module_bindings::AssetObjectAccessPolicy { - match value { - AssetObjectAccessPolicy::Private => { - crate::module_bindings::AssetObjectAccessPolicy::Private - } - AssetObjectAccessPolicy::PublicRead => { - crate::module_bindings::AssetObjectAccessPolicy::PublicRead - } - } -} - -fn map_access_policy_back( - value: crate::module_bindings::AssetObjectAccessPolicy, -) -> AssetObjectAccessPolicy { - match value { - crate::module_bindings::AssetObjectAccessPolicy::Private => { - AssetObjectAccessPolicy::Private - } - crate::module_bindings::AssetObjectAccessPolicy::PublicRead => { - AssetObjectAccessPolicy::PublicRead - } - } -} - -fn map_runtime_platform_theme(value: RuntimePlatformTheme) -> BindingRuntimePlatformTheme { - match value { - RuntimePlatformTheme::Light => BindingRuntimePlatformTheme::Light, - RuntimePlatformTheme::Dark => BindingRuntimePlatformTheme::Dark, - } -} - -fn map_runtime_profile_wallet_ledger_source_type( - value: BindingRuntimeProfileWalletLedgerSourceType, -) -> RuntimeProfileWalletLedgerSourceType { - match value { - BindingRuntimeProfileWalletLedgerSourceType::SnapshotSync => { - RuntimeProfileWalletLedgerSourceType::SnapshotSync - } - } -} - -fn map_runtime_item_reward_item_rarity( - value: DomainRuntimeItemRewardItemRarity, -) -> BindingRuntimeItemRewardItemRarity { - match value { - DomainRuntimeItemRewardItemRarity::Common => BindingRuntimeItemRewardItemRarity::Common, - DomainRuntimeItemRewardItemRarity::Uncommon => BindingRuntimeItemRewardItemRarity::Uncommon, - DomainRuntimeItemRewardItemRarity::Rare => BindingRuntimeItemRewardItemRarity::Rare, - DomainRuntimeItemRewardItemRarity::Epic => BindingRuntimeItemRewardItemRarity::Epic, - DomainRuntimeItemRewardItemRarity::Legendary => { - BindingRuntimeItemRewardItemRarity::Legendary - } - } -} - -fn map_runtime_item_equipment_slot( - value: DomainRuntimeItemEquipmentSlot, -) -> BindingRuntimeItemEquipmentSlot { - match value { - DomainRuntimeItemEquipmentSlot::Weapon => BindingRuntimeItemEquipmentSlot::Weapon, - DomainRuntimeItemEquipmentSlot::Armor => BindingRuntimeItemEquipmentSlot::Armor, - DomainRuntimeItemEquipmentSlot::Relic => BindingRuntimeItemEquipmentSlot::Relic, - } -} - -fn map_custom_world_theme_mode(value: DomainCustomWorldThemeMode) -> BindingCustomWorldThemeMode { - match value { - DomainCustomWorldThemeMode::Martial => BindingCustomWorldThemeMode::Martial, - DomainCustomWorldThemeMode::Arcane => BindingCustomWorldThemeMode::Arcane, - DomainCustomWorldThemeMode::Machina => BindingCustomWorldThemeMode::Machina, - DomainCustomWorldThemeMode::Tide => BindingCustomWorldThemeMode::Tide, - DomainCustomWorldThemeMode::Rift => BindingCustomWorldThemeMode::Rift, - DomainCustomWorldThemeMode::Mythic => BindingCustomWorldThemeMode::Mythic, - } -} - -fn map_battle_mode(value: DomainBattleMode) -> BindingBattleMode { - match value { - DomainBattleMode::Fight => BindingBattleMode::Fight, - DomainBattleMode::Spar => BindingBattleMode::Spar, - } -} - -fn map_runtime_platform_theme_back(value: BindingRuntimePlatformTheme) -> RuntimePlatformTheme { - match value { - BindingRuntimePlatformTheme::Light => RuntimePlatformTheme::Light, - BindingRuntimePlatformTheme::Dark => RuntimePlatformTheme::Dark, - } -} - -fn map_runtime_item_reward_item_rarity_back( - value: BindingRuntimeItemRewardItemRarity, -) -> DomainRuntimeItemRewardItemRarity { - match value { - BindingRuntimeItemRewardItemRarity::Common => DomainRuntimeItemRewardItemRarity::Common, - BindingRuntimeItemRewardItemRarity::Uncommon => DomainRuntimeItemRewardItemRarity::Uncommon, - BindingRuntimeItemRewardItemRarity::Rare => DomainRuntimeItemRewardItemRarity::Rare, - BindingRuntimeItemRewardItemRarity::Epic => DomainRuntimeItemRewardItemRarity::Epic, - BindingRuntimeItemRewardItemRarity::Legendary => { - DomainRuntimeItemRewardItemRarity::Legendary - } - } -} - -fn map_runtime_item_equipment_slot_back( - value: BindingRuntimeItemEquipmentSlot, -) -> DomainRuntimeItemEquipmentSlot { - match value { - BindingRuntimeItemEquipmentSlot::Weapon => DomainRuntimeItemEquipmentSlot::Weapon, - BindingRuntimeItemEquipmentSlot::Armor => DomainRuntimeItemEquipmentSlot::Armor, - BindingRuntimeItemEquipmentSlot::Relic => DomainRuntimeItemEquipmentSlot::Relic, - } -} - -fn map_custom_world_theme_mode_back( - value: BindingCustomWorldThemeMode, -) -> DomainCustomWorldThemeMode { - match value { - BindingCustomWorldThemeMode::Martial => DomainCustomWorldThemeMode::Martial, - BindingCustomWorldThemeMode::Arcane => DomainCustomWorldThemeMode::Arcane, - BindingCustomWorldThemeMode::Machina => DomainCustomWorldThemeMode::Machina, - BindingCustomWorldThemeMode::Tide => DomainCustomWorldThemeMode::Tide, - BindingCustomWorldThemeMode::Rift => DomainCustomWorldThemeMode::Rift, - BindingCustomWorldThemeMode::Mythic => DomainCustomWorldThemeMode::Mythic, - } -} - -fn map_custom_world_publication_status(value: BindingCustomWorldPublicationStatus) -> &'static str { - match value { - BindingCustomWorldPublicationStatus::Draft => "draft", - BindingCustomWorldPublicationStatus::Published => "published", - } -} - -fn map_rpg_agent_stage(value: crate::module_bindings::RpgAgentStage) -> String { - match value { - crate::module_bindings::RpgAgentStage::CollectingIntent => "collecting_intent", - crate::module_bindings::RpgAgentStage::Clarifying => "clarifying", - crate::module_bindings::RpgAgentStage::FoundationReview => "foundation_review", - crate::module_bindings::RpgAgentStage::ObjectRefining => "object_refining", - crate::module_bindings::RpgAgentStage::VisualRefining => "visual_refining", - crate::module_bindings::RpgAgentStage::LongTailReview => "long_tail_review", - crate::module_bindings::RpgAgentStage::ReadyToPublish => "ready_to_publish", - crate::module_bindings::RpgAgentStage::Published => "published", - crate::module_bindings::RpgAgentStage::Error => "error", - } - .to_string() -} - -fn parse_puzzle_agent_stage_record( - value: &str, -) -> Result { - match value.trim() { - "collecting_anchors" => Ok(crate::module_bindings::PuzzleAgentStage::CollectingAnchors), - "draft_ready" => Ok(crate::module_bindings::PuzzleAgentStage::DraftReady), - "image_refining" => Ok(crate::module_bindings::PuzzleAgentStage::ImageRefining), - "ready_to_publish" => Ok(crate::module_bindings::PuzzleAgentStage::ReadyToPublish), - "published" => Ok(crate::module_bindings::PuzzleAgentStage::Published), - other => Err(SpacetimeClientError::Runtime(format!( - "未知 puzzle agent stage: {other}" - ))), - } -} - -fn parse_rpg_agent_stage_record( - value: &str, -) -> Result { - match value.trim() { - "collecting_intent" => Ok(crate::module_bindings::RpgAgentStage::CollectingIntent), - "clarifying" => Ok(crate::module_bindings::RpgAgentStage::Clarifying), - "foundation_review" => Ok(crate::module_bindings::RpgAgentStage::FoundationReview), - "object_refining" => Ok(crate::module_bindings::RpgAgentStage::ObjectRefining), - "visual_refining" => Ok(crate::module_bindings::RpgAgentStage::VisualRefining), - "long_tail_review" => Ok(crate::module_bindings::RpgAgentStage::LongTailReview), - "ready_to_publish" => Ok(crate::module_bindings::RpgAgentStage::ReadyToPublish), - "published" => Ok(crate::module_bindings::RpgAgentStage::Published), - "error" => Ok(crate::module_bindings::RpgAgentStage::Error), - other => Err(SpacetimeClientError::Runtime(format!( - "未知 rpg agent stage: {other}" - ))), - } -} - -fn format_rpg_agent_message_role( - value: crate::module_bindings::RpgAgentMessageRole, -) -> &'static str { - match value { - crate::module_bindings::RpgAgentMessageRole::User => "user", - crate::module_bindings::RpgAgentMessageRole::Assistant => "assistant", - crate::module_bindings::RpgAgentMessageRole::System => "system", - } -} - -fn format_rpg_agent_message_kind( - value: crate::module_bindings::RpgAgentMessageKind, -) -> &'static str { - match value { - crate::module_bindings::RpgAgentMessageKind::Chat => "chat", - crate::module_bindings::RpgAgentMessageKind::Clarification => "clarification", - crate::module_bindings::RpgAgentMessageKind::Summary => "summary", - crate::module_bindings::RpgAgentMessageKind::Checkpoint => "checkpoint", - crate::module_bindings::RpgAgentMessageKind::Warning => "warning", - crate::module_bindings::RpgAgentMessageKind::ActionResult => "action_result", - } -} - -fn format_rpg_agent_operation_type( - value: crate::module_bindings::RpgAgentOperationType, -) -> &'static str { - match value { - crate::module_bindings::RpgAgentOperationType::ProcessMessage => "process_message", - crate::module_bindings::RpgAgentOperationType::DraftFoundation => "draft_foundation", - crate::module_bindings::RpgAgentOperationType::UpdateDraftCard => "update_draft_card", - crate::module_bindings::RpgAgentOperationType::SyncResultProfile => "sync_result_profile", - crate::module_bindings::RpgAgentOperationType::GenerateCharacters => "generate_characters", - crate::module_bindings::RpgAgentOperationType::GenerateLandmarks => "generate_landmarks", - crate::module_bindings::RpgAgentOperationType::GenerateRoleAssets => "generate_role_assets", - crate::module_bindings::RpgAgentOperationType::SyncRoleAssets => "sync_role_assets", - crate::module_bindings::RpgAgentOperationType::GenerateSceneAssets => { - "generate_scene_assets" - } - crate::module_bindings::RpgAgentOperationType::SyncSceneAssets => "sync_scene_assets", - crate::module_bindings::RpgAgentOperationType::ExpandLongTail => "expand_long_tail", - crate::module_bindings::RpgAgentOperationType::PublishWorld => "publish_world", - crate::module_bindings::RpgAgentOperationType::RevertCheckpoint => "revert_checkpoint", - } -} - -fn format_rpg_agent_operation_status( - value: crate::module_bindings::RpgAgentOperationStatus, -) -> &'static str { - match value { - crate::module_bindings::RpgAgentOperationStatus::Queued => "queued", - crate::module_bindings::RpgAgentOperationStatus::Running => "running", - crate::module_bindings::RpgAgentOperationStatus::Completed => "completed", - crate::module_bindings::RpgAgentOperationStatus::Failed => "failed", - } -} - -fn parse_rpg_agent_operation_status_record( - value: &str, -) -> Result { - match value.trim() { - "queued" => Ok(crate::module_bindings::RpgAgentOperationStatus::Queued), - "running" => Ok(crate::module_bindings::RpgAgentOperationStatus::Running), - "completed" => Ok(crate::module_bindings::RpgAgentOperationStatus::Completed), - "failed" => Ok(crate::module_bindings::RpgAgentOperationStatus::Failed), - other => Err(SpacetimeClientError::Runtime(format!( - "未知 rpg agent operation status: {other}" - ))), - } -} - -fn format_rpg_agent_draft_card_kind( - value: crate::module_bindings::RpgAgentDraftCardKind, -) -> &'static str { - match value { - crate::module_bindings::RpgAgentDraftCardKind::World => "world", - crate::module_bindings::RpgAgentDraftCardKind::Camp => "camp", - crate::module_bindings::RpgAgentDraftCardKind::Faction => "faction", - crate::module_bindings::RpgAgentDraftCardKind::Character => "character", - crate::module_bindings::RpgAgentDraftCardKind::Landmark => "landmark", - crate::module_bindings::RpgAgentDraftCardKind::Thread => "thread", - crate::module_bindings::RpgAgentDraftCardKind::Chapter => "chapter", - crate::module_bindings::RpgAgentDraftCardKind::SceneChapter => "scene_chapter", - crate::module_bindings::RpgAgentDraftCardKind::Carrier => "carrier", - crate::module_bindings::RpgAgentDraftCardKind::SidequestSeed => "sidequest_seed", - } -} - -fn format_rpg_agent_draft_card_status( - value: crate::module_bindings::RpgAgentDraftCardStatus, -) -> &'static str { - match value { - crate::module_bindings::RpgAgentDraftCardStatus::Suggested => "suggested", - crate::module_bindings::RpgAgentDraftCardStatus::Confirmed => "confirmed", - crate::module_bindings::RpgAgentDraftCardStatus::Locked => "locked", - crate::module_bindings::RpgAgentDraftCardStatus::Warning => "warning", - } -} - -fn format_custom_world_role_asset_status_back( - value: crate::module_bindings::CustomWorldRoleAssetStatus, -) -> String { - match value { - crate::module_bindings::CustomWorldRoleAssetStatus::Missing => "missing", - crate::module_bindings::CustomWorldRoleAssetStatus::VisualReady => "visual_ready", - crate::module_bindings::CustomWorldRoleAssetStatus::AnimationsReady => "animations_ready", - crate::module_bindings::CustomWorldRoleAssetStatus::Complete => "complete", - } - .to_string() -} - -fn map_big_fish_asset_kind_input( - value: &str, -) -> Result { - match value.trim() { - "level_main_image" => Ok(BindingBigFishAssetKind::LevelMainImage), - "level_motion" => Ok(BindingBigFishAssetKind::LevelMotion), - "stage_background" => Ok(BindingBigFishAssetKind::StageBackground), - other => Err(SpacetimeClientError::Runtime(format!( - "big fish asset kind `{other}` 当前尚未支持" - ))), - } -} - -fn format_big_fish_creation_stage(value: BindingBigFishCreationStage) -> &'static str { - match value { - BindingBigFishCreationStage::CollectingAnchors => "collecting_anchors", - BindingBigFishCreationStage::DraftReady => "draft_ready", - BindingBigFishCreationStage::AssetRefining => "asset_refining", - BindingBigFishCreationStage::ReadyToPublish => "ready_to_publish", - BindingBigFishCreationStage::Published => "published", - } -} - -fn parse_big_fish_creation_stage_record( - value: &str, -) -> Result { - match value.trim() { - "collecting_anchors" => Ok(BindingBigFishCreationStage::CollectingAnchors), - "draft_ready" => Ok(BindingBigFishCreationStage::DraftReady), - "asset_refining" => Ok(BindingBigFishCreationStage::AssetRefining), - "ready_to_publish" => Ok(BindingBigFishCreationStage::ReadyToPublish), - "published" => Ok(BindingBigFishCreationStage::Published), - other => Err(SpacetimeClientError::Runtime(format!( - "未知 big fish creation stage: {other}" - ))), - } -} - -fn format_big_fish_anchor_status(value: BindingBigFishAnchorStatus) -> &'static str { - match value { - BindingBigFishAnchorStatus::Confirmed => "confirmed", - BindingBigFishAnchorStatus::Inferred => "inferred", - BindingBigFishAnchorStatus::Missing => "missing", - BindingBigFishAnchorStatus::Locked => "locked", - } -} - -fn format_big_fish_agent_message_role(value: BindingBigFishAgentMessageRole) -> &'static str { - match value { - BindingBigFishAgentMessageRole::User => "user", - BindingBigFishAgentMessageRole::Assistant => "assistant", - BindingBigFishAgentMessageRole::System => "system", - } -} - -fn format_big_fish_agent_message_kind(value: BindingBigFishAgentMessageKind) -> &'static str { - match value { - BindingBigFishAgentMessageKind::Chat => "chat", - BindingBigFishAgentMessageKind::Summary => "summary", - BindingBigFishAgentMessageKind::ActionResult => "action_result", - BindingBigFishAgentMessageKind::Warning => "warning", - } -} - -fn format_big_fish_asset_kind(value: BindingBigFishAssetKind) -> &'static str { - match value { - BindingBigFishAssetKind::LevelMainImage => "level_main_image", - BindingBigFishAssetKind::LevelMotion => "level_motion", - BindingBigFishAssetKind::StageBackground => "stage_background", - } -} - -fn format_big_fish_asset_status(value: BindingBigFishAssetStatus) -> &'static str { - match value { - BindingBigFishAssetStatus::Missing => "missing", - BindingBigFishAssetStatus::Ready => "ready", - } -} - -fn format_big_fish_run_status(value: BindingBigFishRunStatus) -> &'static str { - match value { - BindingBigFishRunStatus::Running => "running", - BindingBigFishRunStatus::Won => "won", - BindingBigFishRunStatus::Failed => "failed", - } -} - -fn format_custom_world_theme_mode(value: DomainCustomWorldThemeMode) -> &'static str { - match value { - DomainCustomWorldThemeMode::Martial => "martial", - DomainCustomWorldThemeMode::Arcane => "arcane", - DomainCustomWorldThemeMode::Machina => "machina", - DomainCustomWorldThemeMode::Tide => "tide", - DomainCustomWorldThemeMode::Rift => "rift", - DomainCustomWorldThemeMode::Mythic => "mythic", - } -} - -fn map_battle_mode_back(value: BindingBattleMode) -> DomainBattleMode { - match value { - BindingBattleMode::Fight => DomainBattleMode::Fight, - BindingBattleMode::Spar => DomainBattleMode::Spar, - } -} - -fn map_runtime_browse_history_theme_mode_back( - value: BindingRuntimeBrowseHistoryThemeMode, -) -> RuntimeBrowseHistoryThemeMode { - match value { - BindingRuntimeBrowseHistoryThemeMode::Martial => RuntimeBrowseHistoryThemeMode::Martial, - BindingRuntimeBrowseHistoryThemeMode::Arcane => RuntimeBrowseHistoryThemeMode::Arcane, - BindingRuntimeBrowseHistoryThemeMode::Machina => RuntimeBrowseHistoryThemeMode::Machina, - BindingRuntimeBrowseHistoryThemeMode::Tide => RuntimeBrowseHistoryThemeMode::Tide, - BindingRuntimeBrowseHistoryThemeMode::Rift => RuntimeBrowseHistoryThemeMode::Rift, - BindingRuntimeBrowseHistoryThemeMode::Mythic => RuntimeBrowseHistoryThemeMode::Mythic, - } -} - -fn map_story_session_status(value: BindingStorySessionStatus) -> DomainStorySessionStatus { - match value { - BindingStorySessionStatus::Active => DomainStorySessionStatus::Active, - BindingStorySessionStatus::Completed => DomainStorySessionStatus::Completed, - BindingStorySessionStatus::Archived => DomainStorySessionStatus::Archived, - } -} - -fn map_battle_status(value: BindingBattleStatus) -> DomainBattleStatus { - match value { - BindingBattleStatus::Ongoing => DomainBattleStatus::Ongoing, - BindingBattleStatus::Resolved => DomainBattleStatus::Resolved, - BindingBattleStatus::Aborted => DomainBattleStatus::Aborted, - } -} - -fn map_story_event_kind(value: BindingStoryEventKind) -> DomainStoryEventKind { - match value { - BindingStoryEventKind::SessionStarted => DomainStoryEventKind::SessionStarted, - BindingStoryEventKind::StoryContinued => DomainStoryEventKind::StoryContinued, - } -} - -fn map_ai_task_kind(value: DomainAiTaskKind) -> BindingAiTaskKind { - match value { - DomainAiTaskKind::StoryGeneration => BindingAiTaskKind::StoryGeneration, - DomainAiTaskKind::CharacterChat => BindingAiTaskKind::CharacterChat, - DomainAiTaskKind::NpcChat => BindingAiTaskKind::NpcChat, - DomainAiTaskKind::CustomWorldGeneration => BindingAiTaskKind::CustomWorldGeneration, - DomainAiTaskKind::QuestIntent => BindingAiTaskKind::QuestIntent, - DomainAiTaskKind::RuntimeItemIntent => BindingAiTaskKind::RuntimeItemIntent, - } -} - -fn map_ai_task_stage_kind(value: DomainAiTaskStageKind) -> BindingAiTaskStageKind { - match value { - DomainAiTaskStageKind::PreparePrompt => BindingAiTaskStageKind::PreparePrompt, - DomainAiTaskStageKind::RequestModel => BindingAiTaskStageKind::RequestModel, - DomainAiTaskStageKind::RepairResponse => BindingAiTaskStageKind::RepairResponse, - DomainAiTaskStageKind::NormalizeResult => BindingAiTaskStageKind::NormalizeResult, - DomainAiTaskStageKind::PersistResult => BindingAiTaskStageKind::PersistResult, - } -} - -fn map_ai_result_reference_kind( - value: DomainAiResultReferenceKind, -) -> BindingAiResultReferenceKind { - match value { - DomainAiResultReferenceKind::StorySession => BindingAiResultReferenceKind::StorySession, - DomainAiResultReferenceKind::StoryEvent => BindingAiResultReferenceKind::StoryEvent, - DomainAiResultReferenceKind::CustomWorldProfile => { - BindingAiResultReferenceKind::CustomWorldProfile - } - DomainAiResultReferenceKind::QuestRecord => BindingAiResultReferenceKind::QuestRecord, - DomainAiResultReferenceKind::RuntimeItemRecord => { - BindingAiResultReferenceKind::RuntimeItemRecord - } - DomainAiResultReferenceKind::AssetObject => BindingAiResultReferenceKind::AssetObject, - } -} - -fn format_ai_task_kind(value: BindingAiTaskKind) -> &'static str { - match value { - BindingAiTaskKind::StoryGeneration => "story_generation", - BindingAiTaskKind::CharacterChat => "character_chat", - BindingAiTaskKind::NpcChat => "npc_chat", - BindingAiTaskKind::CustomWorldGeneration => "custom_world_generation", - BindingAiTaskKind::QuestIntent => "quest_intent", - BindingAiTaskKind::RuntimeItemIntent => "runtime_item_intent", - } -} - -fn format_ai_task_status(value: BindingAiTaskStatus) -> &'static str { - match value { - BindingAiTaskStatus::Pending => "pending", - BindingAiTaskStatus::Running => "running", - BindingAiTaskStatus::Completed => "completed", - BindingAiTaskStatus::Failed => "failed", - BindingAiTaskStatus::Cancelled => "cancelled", - } -} - -fn format_ai_task_stage_kind(value: BindingAiTaskStageKind) -> &'static str { - match value { - BindingAiTaskStageKind::PreparePrompt => "prepare_prompt", - BindingAiTaskStageKind::RequestModel => "request_model", - BindingAiTaskStageKind::RepairResponse => "repair_response", - BindingAiTaskStageKind::NormalizeResult => "normalize_result", - BindingAiTaskStageKind::PersistResult => "persist_result", - } -} - -fn format_ai_task_stage_status(value: BindingAiTaskStageStatus) -> &'static str { - match value { - BindingAiTaskStageStatus::Pending => "pending", - BindingAiTaskStageStatus::Running => "running", - BindingAiTaskStageStatus::Completed => "completed", - BindingAiTaskStageStatus::Skipped => "skipped", - } -} - -fn format_ai_result_reference_kind(value: BindingAiResultReferenceKind) -> &'static str { - match value { - BindingAiResultReferenceKind::StorySession => "story_session", - BindingAiResultReferenceKind::StoryEvent => "story_event", - BindingAiResultReferenceKind::CustomWorldProfile => "custom_world_profile", - BindingAiResultReferenceKind::QuestRecord => "quest_record", - BindingAiResultReferenceKind::RuntimeItemRecord => "runtime_item_record", - BindingAiResultReferenceKind::AssetObject => "asset_object", - } -} - -fn map_combat_outcome(value: BindingCombatOutcome) -> DomainCombatOutcome { - match value { - BindingCombatOutcome::Ongoing => DomainCombatOutcome::Ongoing, - BindingCombatOutcome::Victory => DomainCombatOutcome::Victory, - BindingCombatOutcome::SparComplete => DomainCombatOutcome::SparComplete, - BindingCombatOutcome::Escaped => DomainCombatOutcome::Escaped, - } -} - -fn map_runtime_item_reward_item_snapshot( - snapshot: DomainRuntimeItemRewardItemSnapshot, -) -> BindingRuntimeItemRewardItemSnapshot { - BindingRuntimeItemRewardItemSnapshot { - item_id: snapshot.item_id, - category: snapshot.category, - item_name: snapshot.item_name, - description: snapshot.description, - quantity: snapshot.quantity, - rarity: map_runtime_item_reward_item_rarity(snapshot.rarity), - tags: snapshot.tags, - stackable: snapshot.stackable, - stack_key: snapshot.stack_key, - equipment_slot_id: snapshot - .equipment_slot_id - .map(map_runtime_item_equipment_slot), - } -} - -fn map_runtime_item_reward_item_snapshot_back( - snapshot: BindingRuntimeItemRewardItemSnapshot, -) -> DomainRuntimeItemRewardItemSnapshot { - DomainRuntimeItemRewardItemSnapshot { - item_id: snapshot.item_id, - category: snapshot.category, - item_name: snapshot.item_name, - description: snapshot.description, - quantity: snapshot.quantity, - rarity: map_runtime_item_reward_item_rarity_back(snapshot.rarity), - tags: snapshot.tags, - stackable: snapshot.stackable, - stack_key: snapshot.stack_key, - equipment_slot_id: snapshot - .equipment_slot_id - .map(map_runtime_item_equipment_slot_back), - } -} - -fn parse_json_value(value: &str, label: &str) -> Result { - serde_json::from_str::(value) - .map_err(|error| SpacetimeClientError::Runtime(format!("{label} 非法: {error}"))) -} - -fn parse_optional_json_value( - value: Option<&str>, - fallback: serde_json::Value, - label: &str, -) -> Result { - match value.map(str::trim).filter(|value| !value.is_empty()) { - Some(value) => parse_json_value(value, label), - None => Ok(fallback), - } -} - -fn parse_json_array( - value: &str, - label: &str, -) -> Result, SpacetimeClientError> { - match parse_json_value(value, label)? { - serde_json::Value::Array(entries) => Ok(entries), - _ => Err(SpacetimeClientError::Runtime(format!( - "{label} 必须是 JSON array" - ))), - } -} - -fn parse_json_string_array(value: &str, label: &str) -> Result, SpacetimeClientError> { - parse_json_array(value, label)? - .into_iter() - .map(|entry| match entry { - serde_json::Value::String(value) => Ok(value), - _ => Err(SpacetimeClientError::Runtime(format!( - "{label} 必须是 string array" - ))), - }) - .collect() -} - -fn map_custom_world_checkpoint_record( - value: serde_json::Value, -) -> Result { - let object = value.as_object().ok_or_else(|| { - SpacetimeClientError::Runtime("custom world checkpoint 必须是 JSON object".to_string()) - })?; - let checkpoint_id = object - .get("checkpointId") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .ok_or_else(|| { - SpacetimeClientError::Runtime("custom world checkpoint.checkpointId 缺失".to_string()) - })?; - let created_at = object - .get("createdAt") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .ok_or_else(|| { - SpacetimeClientError::Runtime("custom world checkpoint.createdAt 缺失".to_string()) - })?; - let label = object - .get("label") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .ok_or_else(|| { - SpacetimeClientError::Runtime("custom world checkpoint.label 缺失".to_string()) - })?; - - Ok(CustomWorldCheckpointRecord { - checkpoint_id: checkpoint_id.to_string(), - created_at: created_at.to_string(), - label: label.to_string(), - }) -} - -fn parse_supported_actions_json( - value: &str, -) -> Result, SpacetimeClientError> { - parse_json_array(value, "custom world agent supported_actions_json")? - .into_iter() - .map(|entry| { - let object = entry.as_object().ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world supported action 必须是 JSON object".to_string(), - ) - })?; - let action = object - .get("action") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world supported action.action 缺失".to_string(), - ) - })?; - let enabled = object - .get("enabled") - .and_then(serde_json::Value::as_bool) - .ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world supported action.enabled 缺失".to_string(), - ) - })?; - - Ok(CustomWorldSupportedActionRecord { - action: action.to_string(), - enabled, - reason: object - .get("reason") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .map(ToOwned::to_owned), - }) - }) - .collect() -} - -fn parse_custom_world_publish_gate_record( - value: &str, -) -> Result { - let object = parse_json_value(value, "custom world publish_gate_json")? - .as_object() - .cloned() - .ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world publish_gate_json 必须是 JSON object".to_string(), - ) - })?; - - let profile_id = object - .get("profileId") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .ok_or_else(|| { - SpacetimeClientError::Runtime("custom world publish_gate.profileId 缺失".to_string()) - })?; - let blockers = object - .get("blockers") - .and_then(serde_json::Value::as_array) - .ok_or_else(|| { - SpacetimeClientError::Runtime("custom world publish_gate.blockers 缺失".to_string()) - })? - .iter() - .cloned() - .map(|entry| { - let object = entry.as_object().ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world publish gate blocker 必须是 JSON object".to_string(), - ) - })?; - let id = object - .get("id") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world publish gate blocker.id 缺失".to_string(), - ) - })?; - let code = object - .get("code") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world publish gate blocker.code 缺失".to_string(), - ) - })?; - let message = object - .get("message") - .and_then(serde_json::Value::as_str) - .map(str::trim) - .filter(|value| !value.is_empty()) - .ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world publish gate blocker.message 缺失".to_string(), - ) - })?; - - Ok(CustomWorldResultPreviewBlockerRecord { - id: id.to_string(), - code: code.to_string(), - message: message.to_string(), - }) - }) - .collect::, _>>()?; - let blocker_count = object - .get("blockerCount") - .and_then(serde_json::Value::as_u64) - .and_then(|value| u32::try_from(value).ok()) - .ok_or_else(|| { - SpacetimeClientError::Runtime("custom world publish_gate.blockerCount 缺失".to_string()) - })?; - let publish_ready = object - .get("publishReady") - .and_then(serde_json::Value::as_bool) - .ok_or_else(|| { - SpacetimeClientError::Runtime("custom world publish_gate.publishReady 缺失".to_string()) - })?; - let can_enter_world = object - .get("canEnterWorld") - .and_then(serde_json::Value::as_bool) - .ok_or_else(|| { - SpacetimeClientError::Runtime( - "custom world publish_gate.canEnterWorld 缺失".to_string(), - ) - })?; - - Ok(CustomWorldPublishGateRecord { - profile_id: profile_id.to_string(), - blockers, - blocker_count, - publish_ready, - can_enter_world, - }) -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BattleStateRecord { - pub battle_state_id: String, - pub story_session_id: String, - pub runtime_session_id: String, - pub actor_user_id: String, - pub chapter_id: Option, - pub target_npc_id: String, - pub target_name: String, - pub battle_mode: String, - pub status: String, - pub player_hp: i32, - pub player_max_hp: i32, - pub player_mana: i32, - pub player_max_mana: i32, - pub target_hp: i32, - pub target_max_hp: i32, - pub experience_reward: u32, - pub reward_items: Vec, - pub turn_index: u32, - pub last_action_function_id: Option, - pub last_action_text: Option, - pub last_result_text: Option, - pub last_damage_dealt: i32, - pub last_damage_taken: i32, - pub last_outcome: String, - pub version: u32, - pub created_at: String, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ResolveCombatActionRecord { - pub battle_state: BattleStateRecord, - pub damage_dealt: i32, - pub damage_taken: i32, - pub outcome: String, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldLibraryEntryRecord { - pub owner_user_id: String, - pub profile_id: String, - pub public_work_code: Option, - pub author_public_user_code: Option, - pub profile: serde_json::Value, - pub visibility: String, - pub published_at: Option, - pub updated_at: String, - pub author_display_name: String, - pub world_name: String, - pub subtitle: String, - pub summary_text: String, - pub cover_image_src: Option, - pub theme_mode: String, - pub playable_npc_count: u32, - pub landmark_count: u32, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldGalleryEntryRecord { - pub owner_user_id: String, - pub profile_id: String, - pub public_work_code: String, - pub author_public_user_code: String, - pub visibility: String, - pub published_at: Option, - pub updated_at: String, - pub author_display_name: String, - pub world_name: String, - pub subtitle: String, - pub summary_text: String, - pub cover_image_src: Option, - pub theme_mode: String, - pub playable_npc_count: u32, - pub landmark_count: u32, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldLibraryMutationRecord { - pub entry: CustomWorldLibraryEntryRecord, - pub gallery_entry: Option, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldPublishedProfileCompileRecord { - pub profile_id: String, - pub owner_user_id: String, - pub world_name: String, - pub subtitle: String, - pub summary_text: String, - pub theme_mode: String, - pub cover_image_src: Option, - pub playable_npc_count: u32, - pub landmark_count: u32, - pub author_display_name: String, - pub compiled_profile: serde_json::Value, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldPublishWorldRecord { - pub compiled_record: CustomWorldPublishedProfileCompileRecord, - pub entry: CustomWorldLibraryEntryRecord, - pub gallery_entry: Option, - pub session_stage: String, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldAgentMessageRecord { - pub message_id: String, - pub role: String, - pub kind: String, - pub text: String, - pub created_at: String, - pub related_operation_id: Option, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldAgentOperationRecord { - pub operation_id: String, - pub operation_type: String, - pub status: String, - pub phase_label: String, - pub phase_detail: String, - pub progress: u32, - pub error_message: Option, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldDraftCardRecord { - pub card_id: String, - pub kind: String, - pub title: String, - pub subtitle: String, - pub summary: String, - pub status: String, - pub linked_ids: Vec, - pub warning_count: u32, - pub asset_status: Option, - pub asset_status_label: Option, - pub detail_payload: Option, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldSupportedActionRecord { - pub action: String, - pub enabled: bool, - pub reason: Option, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldCheckpointRecord { - pub checkpoint_id: String, - pub created_at: String, - pub label: String, -} - -// 兼容并行 custom world facade 中仍在使用的旧命名,避免本轮 module-npc 收口被无关改动阻塞。 -pub type CustomWorldAgentCheckpointRecord = CustomWorldCheckpointRecord; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldResultPreviewBlockerRecord { - pub id: String, - pub code: String, - pub message: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldPublishGateRecord { - pub profile_id: String, - pub blockers: Vec, - pub blocker_count: u32, - pub publish_ready: bool, - pub can_enter_world: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldWorkSummaryRecord { - pub work_id: String, - pub source_type: String, - pub status: String, - pub title: String, - pub subtitle: String, - pub summary: String, - pub cover_image_src: Option, - pub cover_render_mode: Option, - pub cover_character_image_srcs: Vec, - pub updated_at: String, - pub published_at: Option, - pub stage: Option, - pub stage_label: Option, - pub playable_npc_count: u32, - pub landmark_count: u32, - pub role_visual_ready_count: Option, - pub role_animation_ready_count: Option, - pub role_asset_summary_label: Option, - pub session_id: Option, - pub profile_id: Option, - pub can_resume: bool, - pub can_enter_world: bool, - pub blocker_count: u32, - pub publish_ready: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldDraftCardDetailSectionRecord { - pub section_id: String, - pub label: String, - pub value: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldDraftCardDetailRecord { - pub card_id: String, - pub kind: String, - pub title: String, - pub sections: Vec, - pub linked_ids: Vec, - pub locked: bool, - pub editable: bool, - pub editable_section_ids: Vec, - pub warning_messages: Vec, - pub asset_status: Option, - pub asset_status_label: Option, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldAgentSessionRecord { - pub session_id: String, - pub seed_text: String, - pub current_turn: u32, - pub anchor_content: serde_json::Value, - pub progress_percent: u32, - pub last_assistant_reply: Option, - pub stage: String, - pub focus_card_id: Option, - pub creator_intent: serde_json::Value, - pub creator_intent_readiness: serde_json::Value, - pub anchor_pack: serde_json::Value, - pub lock_state: serde_json::Value, - pub draft_profile: serde_json::Value, - pub messages: Vec, - pub draft_cards: Vec, - pub pending_clarifications: Vec, - pub suggested_actions: Vec, - pub recommended_replies: Vec, - pub quality_findings: Vec, - pub asset_coverage: serde_json::Value, - pub checkpoints: Vec, - pub supported_actions: Vec, - pub publish_gate: Option, - pub result_preview: Option, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldProfileUpsertRecordInput { - pub profile_id: String, - pub owner_user_id: String, - pub public_work_code: Option, - pub author_public_user_code: Option, - pub source_agent_session_id: Option, - pub world_name: String, - pub subtitle: String, - pub summary_text: String, - pub theme_mode: DomainCustomWorldThemeMode, - pub cover_image_src: Option, - pub profile_payload_json: String, - pub playable_npc_count: u32, - pub landmark_count: u32, - pub author_display_name: String, - pub updated_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldPublishWorldRecordInput { - pub session_id: String, - pub profile_id: String, - pub owner_user_id: String, - pub public_work_code: Option, - pub author_public_user_code: String, - pub draft_profile_json: String, - pub legacy_result_profile_json: Option, - pub setting_text: String, - pub author_display_name: String, - pub published_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldAgentSessionCreateRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub welcome_message_id: String, - pub welcome_message_text: String, - pub anchor_content_json: String, - pub creator_intent_json: Option, - pub creator_intent_readiness_json: String, - pub anchor_pack_json: Option, - pub lock_state_json: Option, - pub draft_profile_json: Option, - pub pending_clarifications_json: String, - pub suggested_actions_json: String, - pub recommended_replies_json: String, - pub quality_findings_json: String, - pub asset_coverage_json: String, - pub checkpoints_json: String, - pub created_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldAgentMessageSubmitRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub user_message_id: String, - pub user_message_text: String, - pub operation_id: String, - pub submitted_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldAgentMessageFinalizeRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub operation_id: String, - pub assistant_message_id: Option, - pub assistant_reply_text: Option, - pub phase_label: String, - pub phase_detail: String, - pub operation_status: String, - pub operation_progress: u32, - pub stage: String, - pub progress_percent: u32, - pub focus_card_id: Option, - pub anchor_content_json: String, - pub creator_intent_json: Option, - pub creator_intent_readiness_json: String, - pub anchor_pack_json: Option, - pub draft_profile_json: Option, - pub pending_clarifications_json: String, - pub suggested_actions_json: String, - pub recommended_replies_json: String, - pub quality_findings_json: String, - pub asset_coverage_json: String, - pub error_message: Option, - pub updated_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomWorldAgentActionExecuteRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub operation_id: String, - pub action: String, - pub payload_json: Option, - pub submitted_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CustomWorldAgentActionExecuteRecord { - pub operation: CustomWorldAgentOperationRecord, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleAgentSessionCreateRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub welcome_message_id: String, - pub welcome_message_text: String, - pub created_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleAgentMessageSubmitRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub user_message_id: String, - pub user_message_text: String, - pub submitted_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleAgentMessageFinalizeRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub assistant_message_id: Option, - pub assistant_reply_text: Option, - pub stage: String, - pub progress_percent: u32, - pub anchor_pack_json: String, - pub error_message: Option, - pub updated_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleGeneratedImagesSaveRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub candidates_json: String, - pub saved_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleSelectCoverImageRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub candidate_id: String, - pub selected_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzlePublishRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub work_id: String, - pub profile_id: String, - pub author_display_name: String, - pub level_name: Option, - pub summary: Option, - pub theme_tags: Option>, - pub published_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleWorkUpsertRecordInput { - pub profile_id: String, - pub owner_user_id: String, - pub level_name: String, - pub summary: String, - pub theme_tags: Vec, - pub cover_image_src: Option, - pub cover_asset_id: Option, - pub updated_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleRunStartRecordInput { - pub run_id: String, - pub owner_user_id: String, - pub profile_id: String, - pub started_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleRunSwapRecordInput { - pub run_id: String, - pub owner_user_id: String, - pub first_piece_id: String, - pub second_piece_id: String, - pub swapped_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleRunDragRecordInput { - pub run_id: String, - pub owner_user_id: String, - pub piece_id: String, - pub target_row: u32, - pub target_col: u32, - pub dragged_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleRunNextLevelRecordInput { - pub run_id: String, - pub owner_user_id: String, - pub advanced_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleAnchorItemRecord { - pub key: String, - pub label: String, - pub value: String, - pub status: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleAnchorPackRecord { - pub theme_promise: PuzzleAnchorItemRecord, - pub visual_subject: PuzzleAnchorItemRecord, - pub visual_mood: PuzzleAnchorItemRecord, - pub composition_hooks: PuzzleAnchorItemRecord, - pub tags_and_forbidden: PuzzleAnchorItemRecord, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleCreatorIntentRecord { - pub source_mode: String, - pub raw_messages_summary: String, - pub theme_promise: String, - pub visual_subject: String, - pub visual_mood: Vec, - pub composition_hooks: Vec, - pub theme_tags: Vec, - pub forbidden_directives: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleGeneratedImageCandidateRecord { - pub candidate_id: String, - pub image_src: String, - pub asset_id: String, - pub prompt: String, - pub actual_prompt: Option, - pub source_type: String, - pub selected: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleResultDraftRecord { - pub level_name: String, - pub summary: String, - pub theme_tags: Vec, - pub forbidden_directives: Vec, - pub creator_intent: Option, - pub anchor_pack: PuzzleAnchorPackRecord, - pub candidates: Vec, - pub selected_candidate_id: Option, - pub cover_image_src: Option, - pub cover_asset_id: Option, - pub generation_status: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleAgentMessageRecord { - pub message_id: String, - pub role: String, - pub kind: String, - pub text: String, - pub created_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleAgentSuggestedActionRecord { - pub action_id: String, - pub action_type: String, - pub label: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleResultPreviewBlockerRecord { - pub blocker_id: String, - pub code: String, - pub message: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleResultPreviewFindingRecord { - pub finding_id: String, - pub severity: String, - pub code: String, - pub message: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleResultPreviewRecord { - pub draft: PuzzleResultDraftRecord, - pub blockers: Vec, - pub quality_findings: Vec, - pub publish_ready: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleAgentSessionRecord { - pub session_id: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: String, - pub anchor_pack: PuzzleAnchorPackRecord, - pub draft: Option, - pub messages: Vec, - pub last_assistant_reply: Option, - pub published_profile_id: Option, - pub suggested_actions: Vec, - pub result_preview: Option, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleWorkProfileRecord { - pub work_id: String, - pub profile_id: String, - pub owner_user_id: String, - pub source_session_id: Option, - pub author_display_name: String, - pub level_name: String, - pub summary: String, - pub theme_tags: Vec, - pub cover_image_src: Option, - pub cover_asset_id: Option, - pub publication_status: String, - pub updated_at: String, - pub published_at: Option, - pub play_count: u32, - pub publish_ready: bool, - pub anchor_pack: PuzzleAnchorPackRecord, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleCellPositionRecord { - pub row: u32, - pub col: u32, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzlePieceStateRecord { - pub piece_id: String, - pub correct_row: u32, - pub correct_col: u32, - pub current_row: u32, - pub current_col: u32, - pub merged_group_id: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleMergedGroupRecord { - pub group_id: String, - pub piece_ids: Vec, - pub occupied_cells: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleBoardRecord { - pub rows: u32, - pub cols: u32, - pub pieces: Vec, - pub merged_groups: Vec, - pub selected_piece_id: Option, - pub all_tiles_resolved: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleRuntimeLevelRecord { - pub run_id: String, - pub level_index: u32, - pub grid_size: u32, - pub profile_id: String, - pub level_name: String, - pub author_display_name: String, - pub theme_tags: Vec, - pub cover_image_src: Option, - pub board: PuzzleBoardRecord, - pub status: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PuzzleRunRecord { - pub run_id: String, - pub entry_profile_id: String, - pub cleared_level_count: u32, - pub current_level_index: u32, - pub current_grid_size: u32, - pub played_profile_ids: Vec, - pub previous_level_tags: Vec, - pub current_level: Option, - pub recommended_next_profile_id: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishSessionCreateRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub seed_text: String, - pub welcome_message_id: String, - pub welcome_message_text: String, - pub created_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishMessageSubmitRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub user_message_id: String, - pub user_message_text: String, - pub assistant_message_id: String, - pub submitted_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishMessageFinalizeRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub assistant_message_id: Option, - pub assistant_reply_text: Option, - pub stage: String, - pub progress_percent: u32, - pub anchor_pack_json: String, - pub error_message: Option, - pub updated_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishAssetGenerateRecordInput { - pub session_id: String, - pub owner_user_id: String, - pub asset_kind: String, - pub level: Option, - pub motion_key: Option, - pub asset_url: Option, - pub generated_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishRunStartRecordInput { - pub run_id: String, - pub session_id: String, - pub owner_user_id: String, - pub started_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BigFishRunInputSubmitRecordInput { - pub run_id: String, - pub owner_user_id: String, - pub input_x: f32, - pub input_y: f32, - pub submitted_at_micros: i64, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishAnchorItemRecord { - pub key: String, - pub label: String, - pub value: String, - pub status: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishAnchorPackRecord { - pub gameplay_promise: BigFishAnchorItemRecord, - pub ecology_visual_theme: BigFishAnchorItemRecord, - pub growth_ladder: BigFishAnchorItemRecord, - pub risk_tempo: BigFishAnchorItemRecord, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BigFishLevelBlueprintRecord { - pub level: u32, - pub name: String, - pub one_line_fantasy: String, - pub silhouette_direction: String, - pub size_ratio: f32, - pub visual_prompt_seed: String, - pub motion_prompt_seed: String, - pub merge_source_level: Option, - pub prey_window: Vec, - pub threat_window: Vec, - pub is_final_level: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishBackgroundBlueprintRecord { - pub theme: String, - pub color_mood: String, - pub foreground_hints: String, - pub midground_composition: String, - pub background_depth: String, - pub safe_play_area_hint: String, - pub spawn_edge_hint: String, - pub background_prompt_seed: String, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BigFishRuntimeParamsRecord { - pub level_count: u32, - pub merge_count_per_upgrade: u32, - pub spawn_target_count: u32, - pub leader_move_speed: f32, - pub follower_catch_up_speed: f32, - pub offscreen_cull_seconds: f32, - pub prey_spawn_delta_levels: Vec, - pub threat_spawn_delta_levels: Vec, - pub win_level: u32, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BigFishGameDraftRecord { - pub title: String, - pub subtitle: String, - pub core_fun: String, - pub ecology_theme: String, - pub levels: Vec, - pub background: BigFishBackgroundBlueprintRecord, - pub runtime_params: BigFishRuntimeParamsRecord, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishAgentMessageRecord { - pub message_id: String, - pub role: String, - pub kind: String, - pub text: String, - pub created_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishAssetSlotRecord { - pub slot_id: String, - pub asset_kind: String, - pub level: Option, - pub motion_key: Option, - pub status: String, - pub asset_url: Option, - pub prompt_snapshot: String, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct BigFishAssetCoverageRecord { - pub level_main_image_ready_count: u32, - pub level_motion_ready_count: u32, - pub background_ready: bool, - pub required_level_count: u32, - pub publish_ready: bool, - pub blockers: Vec, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BigFishSessionRecord { - pub session_id: String, - pub current_turn: u32, - pub progress_percent: u32, - pub stage: String, - pub anchor_pack: BigFishAnchorPackRecord, - pub draft: Option, - pub asset_slots: Vec, - pub asset_coverage: BigFishAssetCoverageRecord, - pub messages: Vec, - pub last_assistant_reply: Option, - pub publish_ready: bool, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct BigFishWorkSummaryRecord { - pub work_id: String, - pub source_session_id: String, - pub title: String, - pub subtitle: String, - pub summary: String, - pub cover_image_src: Option, - pub status: String, - pub updated_at_micros: i64, - pub publish_ready: bool, - pub level_count: u32, - pub level_main_image_ready_count: u32, - pub level_motion_ready_count: u32, - pub background_ready: bool, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BigFishVector2Record { - pub x: f32, - pub y: f32, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BigFishRuntimeEntityRecord { - pub entity_id: String, - pub level: u32, - pub position: BigFishVector2Record, - pub radius: f32, - pub offscreen_seconds: f32, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct BigFishRuntimeRecord { - pub run_id: String, - pub session_id: String, - pub status: String, - pub tick: u64, - pub player_level: u32, - pub win_level: u32, - pub leader_entity_id: Option, - pub owned_entities: Vec, - pub wild_entities: Vec, - pub camera_center: BigFishVector2Record, - pub last_input: BigFishVector2Record, - pub event_log: Vec, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ResolveNpcBattleInteractionInput { - pub npc_interaction: DomainResolveNpcInteractionInput, - pub story_session_id: String, - pub actor_user_id: String, - pub battle_state_id: Option, - pub player_hp: i32, - pub player_max_hp: i32, - pub player_mana: i32, - pub player_max_mana: i32, - pub target_hp: i32, - pub target_max_hp: i32, - pub experience_reward: u32, - pub reward_items: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct AiTaskStageRecord { - pub stage_kind: String, - pub label: String, - pub detail: String, - pub order: u32, - pub status: String, - pub text_output: Option, - pub structured_payload_json: Option, - pub warning_messages: Vec, - pub started_at: Option, - pub completed_at: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct AiResultReferenceRecord { - pub result_ref_id: String, - pub task_id: String, - pub reference_kind: String, - pub reference_id: String, - pub label: Option, - pub created_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct AiTextChunkRecord { - pub chunk_id: String, - pub task_id: String, - pub stage_kind: String, - pub sequence: u32, - pub delta_text: String, - pub created_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct AiTaskRecord { - pub task_id: String, - pub task_kind: String, - pub owner_user_id: String, - pub request_label: String, - pub source_module: String, - pub source_entity_id: Option, - pub request_payload_json: Option, - pub status: String, - pub failure_message: Option, - pub stages: Vec, - pub result_references: Vec, - pub latest_text_output: Option, - pub latest_structured_payload_json: Option, - pub version: u32, - pub created_at: String, - pub started_at: Option, - pub completed_at: Option, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct AiTaskMutationRecord { - pub task: AiTaskRecord, - pub text_chunk: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct NpcStateRecord { - pub npc_state_id: String, - pub runtime_session_id: String, - pub npc_id: String, - pub npc_name: String, - pub affinity: i32, - pub relation_stance: String, - pub help_used: bool, - pub chatted_count: u32, - pub gifts_given: u32, - pub recruited: bool, - pub trade_stock_signature: Option, - pub revealed_facts: Vec, - pub known_attribute_rumors: Vec, - pub first_meaningful_contact_resolved: bool, - pub seen_backstory_chapter_ids: Vec, - pub trust: u8, - pub warmth: u8, - pub ideological_fit: u8, - pub fear_or_guard: u8, - pub loyalty: u8, - pub current_conflict_tag: Option, - pub recent_approvals: Vec, - pub recent_disapprovals: Vec, - pub created_at: String, - pub updated_at: String, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct NpcInteractionRecord { - pub npc_state: NpcStateRecord, - pub interaction_status: String, - pub action_text: String, - pub result_text: String, - pub story_text: Option, - pub battle_mode: Option, - pub encounter_closed: bool, - pub affinity_changed: bool, - pub previous_affinity: i32, - pub next_affinity: i32, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct NpcBattleInteractionRecord { - pub npc_interaction: NpcInteractionRecord, - pub battle_state: BattleStateRecord, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -struct NpcBattleInteractionSnapshot { - interaction: DomainNpcInteractionResult, - battle_state: DomainBattleStateSnapshot, -} - -fn build_battle_state_record(snapshot: DomainBattleStateSnapshot) -> BattleStateRecord { - BattleStateRecord { - battle_state_id: snapshot.battle_state_id, - story_session_id: snapshot.story_session_id, - runtime_session_id: snapshot.runtime_session_id, - actor_user_id: snapshot.actor_user_id, - chapter_id: snapshot.chapter_id, - target_npc_id: snapshot.target_npc_id, - target_name: snapshot.target_name, - battle_mode: snapshot.battle_mode.as_str().to_string(), - status: snapshot.status.as_str().to_string(), - player_hp: snapshot.player_hp, - player_max_hp: snapshot.player_max_hp, - player_mana: snapshot.player_mana, - player_max_mana: snapshot.player_max_mana, - target_hp: snapshot.target_hp, - target_max_hp: snapshot.target_max_hp, - experience_reward: snapshot.experience_reward, - reward_items: snapshot.reward_items, - turn_index: snapshot.turn_index, - last_action_function_id: snapshot.last_action_function_id, - last_action_text: snapshot.last_action_text, - last_result_text: snapshot.last_result_text, - last_damage_dealt: snapshot.last_damage_dealt, - last_damage_taken: snapshot.last_damage_taken, - last_outcome: snapshot.last_outcome.as_str().to_string(), - version: snapshot.version, - created_at: format_timestamp_micros(snapshot.created_at_micros), - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - } -} - -fn build_resolve_combat_action_record( - result: DomainResolveCombatActionResult, -) -> ResolveCombatActionRecord { - ResolveCombatActionRecord { - battle_state: build_battle_state_record(result.snapshot), - damage_dealt: result.damage_dealt, - damage_taken: result.damage_taken, - outcome: result.outcome.as_str().to_string(), - } -} - -fn map_resolve_npc_battle_interaction_input( - input: ResolveNpcBattleInteractionInput, -) -> BindingResolveNpcBattleInteractionInput { - BindingResolveNpcBattleInteractionInput { - npc_interaction: BindingResolveNpcInteractionInput { - runtime_session_id: input.npc_interaction.runtime_session_id, - npc_id: input.npc_interaction.npc_id, - npc_name: input.npc_interaction.npc_name, - interaction_function_id: input.npc_interaction.interaction_function_id, - release_npc_id: input.npc_interaction.release_npc_id, - updated_at_micros: input.npc_interaction.updated_at_micros, - }, - story_session_id: input.story_session_id, - actor_user_id: input.actor_user_id, - battle_state_id: input.battle_state_id, - player_hp: input.player_hp, - player_max_hp: input.player_max_hp, - player_mana: input.player_mana, - player_max_mana: input.player_max_mana, - target_hp: input.target_hp, - target_max_hp: input.target_max_hp, - experience_reward: input.experience_reward, - reward_items: input - .reward_items - .into_iter() - .map(map_runtime_item_reward_item_snapshot) - .collect(), - } -} - -fn validate_npc_battle_interaction_input( - input: &ResolveNpcBattleInteractionInput, -) -> Result<(), SpacetimeClientError> { - let battle_state_input = DomainBattleStateInput { - battle_state_id: input - .battle_state_id - .clone() - .unwrap_or_else(|| "battle_preview".to_string()), - story_session_id: input.story_session_id.clone(), - runtime_session_id: input.npc_interaction.runtime_session_id.clone(), - actor_user_id: input.actor_user_id.clone(), - chapter_id: None, - target_npc_id: input.npc_interaction.npc_id.clone(), - target_name: input.npc_interaction.npc_name.clone(), - battle_mode: DomainBattleMode::Fight, - player_hp: input.player_hp, - player_max_hp: input.player_max_hp, - player_mana: input.player_mana, - player_max_mana: input.player_max_mana, - target_hp: input.target_hp, - target_max_hp: input.target_max_hp, - experience_reward: input.experience_reward, - reward_items: input.reward_items.clone(), - created_at_micros: input.npc_interaction.updated_at_micros, - }; - validate_battle_state_input(&battle_state_input) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?; - for reward_item in input.reward_items.iter().cloned() { - normalize_reward_item_snapshot(reward_item) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?; - } - - Ok(()) -} - -fn build_npc_state_record(snapshot: DomainNpcStateSnapshot) -> NpcStateRecord { - NpcStateRecord { - npc_state_id: snapshot.npc_state_id, - runtime_session_id: snapshot.runtime_session_id, - npc_id: snapshot.npc_id, - npc_name: snapshot.npc_name, - affinity: snapshot.affinity, - relation_stance: format_npc_relation_stance(snapshot.relation_state.stance).to_string(), - help_used: snapshot.help_used, - chatted_count: snapshot.chatted_count, - gifts_given: snapshot.gifts_given, - recruited: snapshot.recruited, - trade_stock_signature: snapshot.trade_stock_signature, - revealed_facts: snapshot.revealed_facts, - known_attribute_rumors: snapshot.known_attribute_rumors, - first_meaningful_contact_resolved: snapshot.first_meaningful_contact_resolved, - seen_backstory_chapter_ids: snapshot.seen_backstory_chapter_ids, - trust: snapshot.stance_profile.trust, - warmth: snapshot.stance_profile.warmth, - ideological_fit: snapshot.stance_profile.ideological_fit, - fear_or_guard: snapshot.stance_profile.fear_or_guard, - loyalty: snapshot.stance_profile.loyalty, - current_conflict_tag: snapshot.stance_profile.current_conflict_tag, - recent_approvals: snapshot.stance_profile.recent_approvals, - recent_disapprovals: snapshot.stance_profile.recent_disapprovals, - created_at: format_timestamp_micros(snapshot.created_at_micros), - updated_at: format_timestamp_micros(snapshot.updated_at_micros), - } -} - -fn build_npc_interaction_record(result: DomainNpcInteractionResult) -> NpcInteractionRecord { - NpcInteractionRecord { - npc_state: build_npc_state_record(result.npc_state), - interaction_status: format_npc_interaction_status(result.interaction_status).to_string(), - action_text: result.action_text, - result_text: result.result_text, - story_text: result.story_text, - battle_mode: result - .battle_mode - .map(|mode| format_npc_interaction_battle_mode(mode).to_string()), - encounter_closed: result.encounter_closed, - affinity_changed: result.affinity_changed, - previous_affinity: result.previous_affinity, - next_affinity: result.next_affinity, - } -} - -fn build_npc_battle_interaction_record( - result: NpcBattleInteractionSnapshot, -) -> NpcBattleInteractionRecord { - NpcBattleInteractionRecord { - npc_interaction: build_npc_interaction_record(result.interaction), - battle_state: build_battle_state_record(result.battle_state), - } -} - -fn format_npc_relation_stance(value: DomainNpcRelationStance) -> &'static str { - match value { - DomainNpcRelationStance::Hostile => "hostile", - DomainNpcRelationStance::Guarded => "guarded", - DomainNpcRelationStance::Neutral => "neutral", - DomainNpcRelationStance::Cooperative => "cooperative", - DomainNpcRelationStance::Bonded => "bonded", - } -} - -fn format_npc_interaction_status(value: DomainNpcInteractionStatus) -> &'static str { - match value { - DomainNpcInteractionStatus::Previewed => "previewed", - DomainNpcInteractionStatus::Dialogue => "dialogue", - DomainNpcInteractionStatus::Resolved => "resolved", - DomainNpcInteractionStatus::Recruited => "recruited", - DomainNpcInteractionStatus::BattlePending => "battle_pending", - DomainNpcInteractionStatus::Left => "left", - } -} - -fn format_npc_interaction_battle_mode(value: DomainNpcInteractionBattleMode) -> &'static str { - match value { - DomainNpcInteractionBattleMode::Fight => "fight", - DomainNpcInteractionBattleMode::Spar => "spar", - } -} - -fn map_inventory_container_kind( - value: BindingInventoryContainerKind, -) -> module_inventory::InventoryContainerKind { - match value { - BindingInventoryContainerKind::Backpack => { - module_inventory::InventoryContainerKind::Backpack - } - BindingInventoryContainerKind::Equipment => { - module_inventory::InventoryContainerKind::Equipment - } - } -} - -fn map_inventory_item_rarity( - value: BindingInventoryItemRarity, -) -> module_inventory::InventoryItemRarity { - match value { - BindingInventoryItemRarity::Common => module_inventory::InventoryItemRarity::Common, - BindingInventoryItemRarity::Uncommon => module_inventory::InventoryItemRarity::Uncommon, - BindingInventoryItemRarity::Rare => module_inventory::InventoryItemRarity::Rare, - BindingInventoryItemRarity::Epic => module_inventory::InventoryItemRarity::Epic, - BindingInventoryItemRarity::Legendary => module_inventory::InventoryItemRarity::Legendary, - } -} - -fn map_inventory_equipment_slot( - value: BindingInventoryEquipmentSlot, -) -> module_inventory::InventoryEquipmentSlot { - match value { - BindingInventoryEquipmentSlot::Weapon => module_inventory::InventoryEquipmentSlot::Weapon, - BindingInventoryEquipmentSlot::Armor => module_inventory::InventoryEquipmentSlot::Armor, - BindingInventoryEquipmentSlot::Relic => module_inventory::InventoryEquipmentSlot::Relic, - } -} - -fn map_inventory_item_source_kind( - value: BindingInventoryItemSourceKind, -) -> module_inventory::InventoryItemSourceKind { - match value { - BindingInventoryItemSourceKind::StoryReward => { - module_inventory::InventoryItemSourceKind::StoryReward - } - BindingInventoryItemSourceKind::QuestReward => { - module_inventory::InventoryItemSourceKind::QuestReward - } - BindingInventoryItemSourceKind::TreasureReward => { - module_inventory::InventoryItemSourceKind::TreasureReward - } - BindingInventoryItemSourceKind::NpcGift => { - module_inventory::InventoryItemSourceKind::NpcGift - } - BindingInventoryItemSourceKind::NpcTrade => { - module_inventory::InventoryItemSourceKind::NpcTrade - } - BindingInventoryItemSourceKind::CombatDrop => { - module_inventory::InventoryItemSourceKind::CombatDrop - } - BindingInventoryItemSourceKind::ForgeCraft => { - module_inventory::InventoryItemSourceKind::ForgeCraft - } - BindingInventoryItemSourceKind::ForgeReforge => { - module_inventory::InventoryItemSourceKind::ForgeReforge - } - BindingInventoryItemSourceKind::ManualPatch => { - module_inventory::InventoryItemSourceKind::ManualPatch - } - } -} - -======= ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) impl fmt::Display for SpacetimeClientError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/server-rs/crates/spacetime-client/src/mapper.rs b/server-rs/crates/spacetime-client/src/mapper.rs index 14dd697f..96cb0c0b 100644 --- a/server-rs/crates/spacetime-client/src/mapper.rs +++ b/server-rs/crates/spacetime-client/src/mapper.rs @@ -1,405 +1,421 @@ use super::*; -pub(crate) fn map_entity_binding_input( - input: module_assets::AssetEntityBindingInput, -) -> AssetEntityBindingInput { - AssetEntityBindingInput { - binding_id: input.binding_id, - asset_object_id: input.asset_object_id, - entity_kind: input.entity_kind, - entity_id: input.entity_id, - slot: input.slot, - asset_kind: input.asset_kind, - owner_user_id: input.owner_user_id, - profile_id: input.profile_id, - updated_at_micros: input.updated_at_micros, +impl From for AssetEntityBindingInput { + fn from(input: module_assets::AssetEntityBindingInput) -> Self { + Self { + binding_id: input.binding_id, + asset_object_id: input.asset_object_id, + entity_kind: input.entity_kind, + entity_id: input.entity_id, + slot: input.slot, + asset_kind: input.asset_kind, + owner_user_id: input.owner_user_id, + profile_id: input.profile_id, + updated_at_micros: input.updated_at_micros, + } } } -pub(crate) fn map_upsert_input(input: module_assets::AssetObjectUpsertInput) -> AssetObjectUpsertInput { - AssetObjectUpsertInput { - asset_object_id: input.asset_object_id, - bucket: input.bucket, - object_key: input.object_key, - access_policy: map_access_policy(input.access_policy), - content_type: input.content_type, - content_length: input.content_length, - content_hash: input.content_hash, - version: input.version, - source_job_id: input.source_job_id, - owner_user_id: input.owner_user_id, - profile_id: input.profile_id, - entity_id: input.entity_id, - asset_kind: input.asset_kind, - updated_at_micros: input.updated_at_micros, +impl From for AssetObjectUpsertInput { + fn from(input: module_assets::AssetObjectUpsertInput) -> Self { + Self { + asset_object_id: input.asset_object_id, + bucket: input.bucket, + object_key: input.object_key, + access_policy: map_access_policy(input.access_policy), + content_type: input.content_type, + content_length: input.content_length, + content_hash: input.content_hash, + version: input.version, + source_job_id: input.source_job_id, + owner_user_id: input.owner_user_id, + profile_id: input.profile_id, + entity_id: input.entity_id, + asset_kind: input.asset_kind, + updated_at_micros: input.updated_at_micros, + } } } -pub(crate) fn map_runtime_setting_get_input( - input: module_runtime::RuntimeSettingGetInput, -) -> RuntimeSettingGetInput { - RuntimeSettingGetInput { - user_id: input.user_id, +impl From for RuntimeSettingGetInput { + fn from(input: module_runtime::RuntimeSettingGetInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_setting_upsert_input( - input: module_runtime::RuntimeSettingUpsertInput, -) -> RuntimeSettingUpsertInput { - RuntimeSettingUpsertInput { - user_id: input.user_id, - music_volume: input.music_volume, - platform_theme: map_runtime_platform_theme(input.platform_theme), - updated_at_micros: input.updated_at_micros, +impl From for RuntimeSettingUpsertInput { + fn from(input: module_runtime::RuntimeSettingUpsertInput) -> Self { + Self { + user_id: input.user_id, + music_volume: input.music_volume, + platform_theme: map_runtime_platform_theme(input.platform_theme), + updated_at_micros: input.updated_at_micros, + } } } -pub(crate) fn map_runtime_browse_history_list_input( - input: module_runtime::RuntimeBrowseHistoryListInput, -) -> RuntimeBrowseHistoryListInput { - RuntimeBrowseHistoryListInput { - user_id: input.user_id, +impl From for RuntimeBrowseHistoryListInput { + fn from(input: module_runtime::RuntimeBrowseHistoryListInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_browse_history_clear_input( - input: module_runtime::RuntimeBrowseHistoryClearInput, -) -> RuntimeBrowseHistoryClearInput { - RuntimeBrowseHistoryClearInput { - user_id: input.user_id, +impl From for RuntimeBrowseHistoryClearInput { + fn from(input: module_runtime::RuntimeBrowseHistoryClearInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_browse_history_sync_input( - input: module_runtime::RuntimeBrowseHistorySyncInput, -) -> RuntimeBrowseHistorySyncInput { - RuntimeBrowseHistorySyncInput { - user_id: input.user_id, - entries: input - .entries - .into_iter() - .map(map_runtime_browse_history_write_input) - .collect(), - updated_at_micros: input.updated_at_micros, +impl From for RuntimeBrowseHistorySyncInput { + fn from(input: module_runtime::RuntimeBrowseHistorySyncInput) -> Self { + Self { + user_id: input.user_id, + entries: input.entries.into_iter().map(Into::into).collect(), + updated_at_micros: input.updated_at_micros, + } } } -pub(crate) fn map_runtime_browse_history_write_input( - input: module_runtime::RuntimeBrowseHistoryWriteInput, -) -> RuntimeBrowseHistoryWriteInput { - RuntimeBrowseHistoryWriteInput { - owner_user_id: input.owner_user_id, - profile_id: input.profile_id, - world_name: input.world_name, - subtitle: input.subtitle, - summary_text: input.summary_text, - cover_image_src: input.cover_image_src, - theme_mode: input.theme_mode, - author_display_name: input.author_display_name, - visited_at: input.visited_at, +impl From for RuntimeBrowseHistoryWriteInput { + fn from(input: module_runtime::RuntimeBrowseHistoryWriteInput) -> Self { + Self { + owner_user_id: input.owner_user_id, + profile_id: input.profile_id, + world_name: input.world_name, + subtitle: input.subtitle, + summary_text: input.summary_text, + cover_image_src: input.cover_image_src, + theme_mode: input.theme_mode, + author_display_name: input.author_display_name, + visited_at: input.visited_at, + } } } -pub(crate) fn map_runtime_profile_dashboard_get_input( - input: module_runtime::RuntimeProfileDashboardGetInput, -) -> RuntimeProfileDashboardGetInput { - RuntimeProfileDashboardGetInput { - user_id: input.user_id, +impl From for RuntimeProfileDashboardGetInput { + fn from(input: module_runtime::RuntimeProfileDashboardGetInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_profile_wallet_ledger_list_input( - input: module_runtime::RuntimeProfileWalletLedgerListInput, -) -> RuntimeProfileWalletLedgerListInput { - RuntimeProfileWalletLedgerListInput { - user_id: input.user_id, +impl From + for RuntimeProfileWalletLedgerListInput +{ + fn from(input: module_runtime::RuntimeProfileWalletLedgerListInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_profile_play_stats_get_input( - input: module_runtime::RuntimeProfilePlayStatsGetInput, -) -> RuntimeProfilePlayStatsGetInput { - RuntimeProfilePlayStatsGetInput { - user_id: input.user_id, +impl From for RuntimeProfilePlayStatsGetInput { + fn from(input: module_runtime::RuntimeProfilePlayStatsGetInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_snapshot_get_input( - input: module_runtime::RuntimeSnapshotGetInput, -) -> RuntimeSnapshotGetInput { - RuntimeSnapshotGetInput { - user_id: input.user_id, +impl From for RuntimeSnapshotGetInput { + fn from(input: module_runtime::RuntimeSnapshotGetInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_snapshot_upsert_input( - input: module_runtime::RuntimeSnapshotUpsertInput, -) -> RuntimeSnapshotUpsertInput { - RuntimeSnapshotUpsertInput { - user_id: input.user_id, - saved_at_micros: input.saved_at_micros, - bottom_tab: input.bottom_tab, - game_state_json: input.game_state_json, - current_story_json: input.current_story_json, - updated_at_micros: input.updated_at_micros, +impl From for RuntimeSnapshotUpsertInput { + fn from(input: module_runtime::RuntimeSnapshotUpsertInput) -> Self { + Self { + user_id: input.user_id, + saved_at_micros: input.saved_at_micros, + bottom_tab: input.bottom_tab, + game_state_json: input.game_state_json, + current_story_json: input.current_story_json, + updated_at_micros: input.updated_at_micros, + } } } -pub(crate) fn map_runtime_snapshot_delete_input( - input: module_runtime::RuntimeSnapshotDeleteInput, -) -> RuntimeSnapshotDeleteInput { - RuntimeSnapshotDeleteInput { - user_id: input.user_id, +impl From for RuntimeSnapshotDeleteInput { + fn from(input: module_runtime::RuntimeSnapshotDeleteInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_profile_save_archive_list_input( - input: module_runtime::RuntimeProfileSaveArchiveListInput, -) -> RuntimeProfileSaveArchiveListInput { - RuntimeProfileSaveArchiveListInput { - user_id: input.user_id, +impl From + for RuntimeProfileSaveArchiveListInput +{ + fn from(input: module_runtime::RuntimeProfileSaveArchiveListInput) -> Self { + Self { + user_id: input.user_id, + } } } -pub(crate) fn map_runtime_profile_save_archive_resume_input( - input: module_runtime::RuntimeProfileSaveArchiveResumeInput, -) -> RuntimeProfileSaveArchiveResumeInput { - RuntimeProfileSaveArchiveResumeInput { - user_id: input.user_id, - world_key: input.world_key, +impl From + for RuntimeProfileSaveArchiveResumeInput +{ + fn from(input: module_runtime::RuntimeProfileSaveArchiveResumeInput) -> Self { + Self { + user_id: input.user_id, + world_key: input.world_key, + } } } -pub(crate) fn map_ai_task_create_input(input: DomainAiTaskCreateInput) -> AiTaskCreateInput { - AiTaskCreateInput { - task_id: input.task_id, - task_kind: map_ai_task_kind(input.task_kind), - owner_user_id: input.owner_user_id, - request_label: input.request_label, - source_module: input.source_module, - source_entity_id: input.source_entity_id, - request_payload_json: input.request_payload_json, - stages: input - .stages - .into_iter() - .map(map_ai_task_stage_blueprint) - .collect(), - created_at_micros: input.created_at_micros, +impl From for AiTaskCreateInput { + fn from(input: DomainAiTaskCreateInput) -> Self { + Self { + task_id: input.task_id, + task_kind: map_ai_task_kind(input.task_kind), + owner_user_id: input.owner_user_id, + request_label: input.request_label, + source_module: input.source_module, + source_entity_id: input.source_entity_id, + request_payload_json: input.request_payload_json, + stages: input.stages.into_iter().map(Into::into).collect(), + created_at_micros: input.created_at_micros, + } } } -pub(crate) fn map_ai_task_start_input(input: DomainAiTaskStartInput) -> AiTaskStartInput { - AiTaskStartInput { - task_id: input.task_id, - started_at_micros: input.started_at_micros, +impl From for AiTaskStartInput { + fn from(input: DomainAiTaskStartInput) -> Self { + Self { + task_id: input.task_id, + started_at_micros: input.started_at_micros, + } } } -pub(crate) fn map_ai_task_stage_start_input( - input: DomainAiTaskStageStartInput, -) -> AiTaskStageStartInput { - AiTaskStageStartInput { - task_id: input.task_id, - stage_kind: map_ai_task_stage_kind(input.stage_kind), - started_at_micros: input.started_at_micros, +impl From for AiTaskStageStartInput { + fn from(input: DomainAiTaskStageStartInput) -> Self { + Self { + task_id: input.task_id, + stage_kind: map_ai_task_stage_kind(input.stage_kind), + started_at_micros: input.started_at_micros, + } } } -pub(crate) fn map_ai_text_chunk_append_input( - input: DomainAiTextChunkAppendInput, -) -> AiTextChunkAppendInput { - AiTextChunkAppendInput { - task_id: input.task_id, - stage_kind: map_ai_task_stage_kind(input.stage_kind), - sequence: input.sequence, - delta_text: input.delta_text, - created_at_micros: input.created_at_micros, +impl From for AiTextChunkAppendInput { + fn from(input: DomainAiTextChunkAppendInput) -> Self { + Self { + task_id: input.task_id, + stage_kind: map_ai_task_stage_kind(input.stage_kind), + sequence: input.sequence, + delta_text: input.delta_text, + created_at_micros: input.created_at_micros, + } } } -pub(crate) fn map_ai_stage_completion_input( - input: DomainAiStageCompletionInput, -) -> AiStageCompletionInput { - AiStageCompletionInput { - task_id: input.task_id, - stage_kind: map_ai_task_stage_kind(input.stage_kind), - text_output: input.text_output, - structured_payload_json: input.structured_payload_json, - warning_messages: input.warning_messages, - completed_at_micros: input.completed_at_micros, +impl From for AiStageCompletionInput { + fn from(input: DomainAiStageCompletionInput) -> Self { + Self { + task_id: input.task_id, + stage_kind: map_ai_task_stage_kind(input.stage_kind), + text_output: input.text_output, + structured_payload_json: input.structured_payload_json, + warning_messages: input.warning_messages, + completed_at_micros: input.completed_at_micros, + } } } -pub(crate) fn map_ai_result_reference_input( - input: DomainAiResultReferenceInput, -) -> AiResultReferenceInput { - AiResultReferenceInput { - task_id: input.task_id, - reference_kind: map_ai_result_reference_kind(input.reference_kind), - reference_id: input.reference_id, - label: input.label, - created_at_micros: input.created_at_micros, +impl From for AiResultReferenceInput { + fn from(input: DomainAiResultReferenceInput) -> Self { + Self { + task_id: input.task_id, + reference_kind: map_ai_result_reference_kind(input.reference_kind), + reference_id: input.reference_id, + label: input.label, + created_at_micros: input.created_at_micros, + } } } -pub(crate) fn map_ai_task_finish_input(input: DomainAiTaskFinishInput) -> AiTaskFinishInput { - AiTaskFinishInput { - task_id: input.task_id, - completed_at_micros: input.completed_at_micros, +impl From for AiTaskFinishInput { + fn from(input: DomainAiTaskFinishInput) -> Self { + Self { + task_id: input.task_id, + completed_at_micros: input.completed_at_micros, + } } } -pub(crate) fn map_ai_task_failure_input(input: DomainAiTaskFailureInput) -> AiTaskFailureInput { - AiTaskFailureInput { - task_id: input.task_id, - failure_message: input.failure_message, - completed_at_micros: input.completed_at_micros, +impl From for AiTaskFailureInput { + fn from(input: DomainAiTaskFailureInput) -> Self { + Self { + task_id: input.task_id, + failure_message: input.failure_message, + completed_at_micros: input.completed_at_micros, + } } } -pub(crate) fn map_ai_task_cancel_input(input: DomainAiTaskCancelInput) -> AiTaskCancelInput { - AiTaskCancelInput { - task_id: input.task_id, - completed_at_micros: input.completed_at_micros, +impl From for AiTaskCancelInput { + fn from(input: DomainAiTaskCancelInput) -> Self { + Self { + task_id: input.task_id, + completed_at_micros: input.completed_at_micros, + } } } -pub(crate) fn map_ai_task_stage_blueprint( - blueprint: DomainAiTaskStageBlueprint, -) -> AiTaskStageBlueprint { - AiTaskStageBlueprint { - stage_kind: map_ai_task_stage_kind(blueprint.stage_kind), - label: blueprint.label, - detail: blueprint.detail, - order: blueprint.order, +impl From for AiTaskStageBlueprint { + fn from(blueprint: DomainAiTaskStageBlueprint) -> Self { + Self { + stage_kind: map_ai_task_stage_kind(blueprint.stage_kind), + label: blueprint.label, + detail: blueprint.detail, + order: blueprint.order, + } } } -pub(crate) fn map_custom_world_profile_upsert_input( - input: CustomWorldProfileUpsertRecordInput, -) -> CustomWorldProfileUpsertInput { - CustomWorldProfileUpsertInput { - profile_id: input.profile_id, - owner_user_id: input.owner_user_id, - public_work_code: input.public_work_code, - author_public_user_code: input.author_public_user_code, - source_agent_session_id: input.source_agent_session_id, - world_name: input.world_name, - subtitle: input.subtitle, - summary_text: input.summary_text, - theme_mode: map_custom_world_theme_mode(input.theme_mode), - cover_image_src: input.cover_image_src, - profile_payload_json: input.profile_payload_json, - playable_npc_count: input.playable_npc_count, - landmark_count: input.landmark_count, - author_display_name: input.author_display_name, - updated_at_micros: input.updated_at_micros, +impl From for CustomWorldProfileUpsertInput { + fn from(input: CustomWorldProfileUpsertRecordInput) -> Self { + Self { + profile_id: input.profile_id, + owner_user_id: input.owner_user_id, + public_work_code: input.public_work_code, + author_public_user_code: input.author_public_user_code, + source_agent_session_id: input.source_agent_session_id, + world_name: input.world_name, + subtitle: input.subtitle, + summary_text: input.summary_text, + theme_mode: map_custom_world_theme_mode(input.theme_mode), + cover_image_src: input.cover_image_src, + profile_payload_json: input.profile_payload_json, + playable_npc_count: input.playable_npc_count, + landmark_count: input.landmark_count, + author_display_name: input.author_display_name, + updated_at_micros: input.updated_at_micros, + } } } -pub(crate) fn map_custom_world_publish_world_input( - input: CustomWorldPublishWorldRecordInput, -) -> CustomWorldPublishWorldInput { - CustomWorldPublishWorldInput { - session_id: input.session_id, - profile_id: input.profile_id, - owner_user_id: input.owner_user_id, - public_work_code: input.public_work_code, - author_public_user_code: input.author_public_user_code, - draft_profile_json: input.draft_profile_json, - legacy_result_profile_json: input.legacy_result_profile_json, - setting_text: input.setting_text, - author_display_name: input.author_display_name, - published_at_micros: input.published_at_micros, +impl From for CustomWorldPublishWorldInput { + fn from(input: CustomWorldPublishWorldRecordInput) -> Self { + Self { + session_id: input.session_id, + profile_id: input.profile_id, + owner_user_id: input.owner_user_id, + public_work_code: input.public_work_code, + author_public_user_code: input.author_public_user_code, + draft_profile_json: input.draft_profile_json, + legacy_result_profile_json: input.legacy_result_profile_json, + setting_text: input.setting_text, + author_display_name: input.author_display_name, + published_at_micros: input.published_at_micros, + } } } -pub(crate) fn map_story_session_input(input: DomainStorySessionInput) -> StorySessionInput { - StorySessionInput { - story_session_id: input.story_session_id, - runtime_session_id: input.runtime_session_id, - actor_user_id: input.actor_user_id, - world_profile_id: input.world_profile_id, - initial_prompt: input.initial_prompt, - opening_summary: input.opening_summary, - created_at_micros: input.created_at_micros, +impl From for StorySessionInput { + fn from(input: DomainStorySessionInput) -> Self { + Self { + story_session_id: input.story_session_id, + runtime_session_id: input.runtime_session_id, + actor_user_id: input.actor_user_id, + world_profile_id: input.world_profile_id, + initial_prompt: input.initial_prompt, + opening_summary: input.opening_summary, + created_at_micros: input.created_at_micros, + } } } -pub(crate) fn map_story_continue_input(input: DomainStoryContinueInput) -> StoryContinueInput { - StoryContinueInput { - story_session_id: input.story_session_id, - event_id: input.event_id, - narrative_text: input.narrative_text, - choice_function_id: input.choice_function_id, - updated_at_micros: input.updated_at_micros, +impl From for StoryContinueInput { + fn from(input: DomainStoryContinueInput) -> Self { + Self { + story_session_id: input.story_session_id, + event_id: input.event_id, + narrative_text: input.narrative_text, + choice_function_id: input.choice_function_id, + updated_at_micros: input.updated_at_micros, + } } } -pub(crate) fn map_story_session_state_input( - input: DomainStorySessionStateInput, -) -> StorySessionStateInput { - StorySessionStateInput { - story_session_id: input.story_session_id, +impl From for StorySessionStateInput { + fn from(input: DomainStorySessionStateInput) -> Self { + Self { + story_session_id: input.story_session_id, + } } } -pub(crate) fn map_runtime_inventory_state_query_input( - input: DomainRuntimeInventoryStateQueryInput, -) -> RuntimeInventoryStateQueryInput { - RuntimeInventoryStateQueryInput { - runtime_session_id: input.runtime_session_id, - actor_user_id: input.actor_user_id, +impl From for RuntimeInventoryStateQueryInput { + fn from(input: DomainRuntimeInventoryStateQueryInput) -> Self { + Self { + runtime_session_id: input.runtime_session_id, + actor_user_id: input.actor_user_id, + } } } -pub(crate) fn map_battle_state_query_input( - input: DomainBattleStateQueryInput, -) -> BattleStateQueryInput { - BattleStateQueryInput { - battle_state_id: input.battle_state_id, +impl From for BattleStateQueryInput { + fn from(input: DomainBattleStateQueryInput) -> Self { + Self { + battle_state_id: input.battle_state_id, + } } } -pub(crate) fn map_battle_state_input(input: DomainBattleStateInput) -> BattleStateInput { - BattleStateInput { - battle_state_id: input.battle_state_id, - story_session_id: input.story_session_id, - runtime_session_id: input.runtime_session_id, - actor_user_id: input.actor_user_id, - chapter_id: input.chapter_id, - target_npc_id: input.target_npc_id, - target_name: input.target_name, - battle_mode: map_battle_mode(input.battle_mode), - player_hp: input.player_hp, - player_max_hp: input.player_max_hp, - player_mana: input.player_mana, - player_max_mana: input.player_max_mana, - target_hp: input.target_hp, - target_max_hp: input.target_max_hp, - experience_reward: input.experience_reward, - reward_items: input - .reward_items - .into_iter() - .map(map_runtime_item_reward_item_snapshot) - .collect(), - created_at_micros: input.created_at_micros, +impl From for BattleStateInput { + fn from(input: DomainBattleStateInput) -> Self { + Self { + battle_state_id: input.battle_state_id, + story_session_id: input.story_session_id, + runtime_session_id: input.runtime_session_id, + actor_user_id: input.actor_user_id, + chapter_id: input.chapter_id, + target_npc_id: input.target_npc_id, + target_name: input.target_name, + battle_mode: map_battle_mode(input.battle_mode), + player_hp: input.player_hp, + player_max_hp: input.player_max_hp, + player_mana: input.player_mana, + player_max_mana: input.player_max_mana, + target_hp: input.target_hp, + target_max_hp: input.target_max_hp, + experience_reward: input.experience_reward, + reward_items: input + .reward_items + .into_iter() + .map(map_runtime_item_reward_item_snapshot) + .collect(), + created_at_micros: input.created_at_micros, + } } } -pub(crate) fn map_resolve_combat_action_input( - input: DomainResolveCombatActionInput, -) -> ResolveCombatActionInput { - ResolveCombatActionInput { - battle_state_id: input.battle_state_id, - function_id: input.function_id, - action_text: input.action_text, - base_damage: input.base_damage, - mana_cost: input.mana_cost, - heal: input.heal, - mana_restore: input.mana_restore, - counter_multiplier_basis_points: input.counter_multiplier_basis_points, - updated_at_micros: input.updated_at_micros, +impl From for ResolveCombatActionInput { + fn from(input: DomainResolveCombatActionInput) -> Self { + Self { + battle_state_id: input.battle_state_id, + function_id: input.function_id, + action_text: input.action_text, + base_damage: input.base_damage, + mana_cost: input.mana_cost, + heal: input.heal, + mana_restore: input.mana_restore, + counter_multiplier_basis_points: input.counter_multiplier_basis_points, + updated_at_micros: input.updated_at_micros, + } } } @@ -482,14 +498,36 @@ pub(crate) fn map_auth_store_snapshot_procedure_result( } pub(crate) fn map_auth_store_snapshot_record( - record: AuthStoreSnapshotRecord, -) -> AuthStoreSnapshotRecord { - AuthStoreSnapshotRecord { + 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 { + if !result.ok { + return Err(SpacetimeClientError::Procedure( + result + .error_message + .unwrap_or_else(|| "SpacetimeDB procedure ??????".to_string()), + )); + } + + let record = result.record.ok_or_else(|| { + SpacetimeClientError::Procedure("SpacetimeDB procedure ???????".to_string()) + })?; + + Ok(AuthStoreSnapshotImportRecord { + 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_runtime_browse_history_procedure_result( result: RuntimeBrowseHistoryProcedureResult, ) -> Result, SpacetimeClientError> { @@ -1297,7 +1335,7 @@ pub(crate) fn map_runtime_profile_wallet_ledger_entry_snapshot( user_id: snapshot.user_id, amount_delta: snapshot.amount_delta, balance_after: snapshot.balance_after, - source_type: map_runtime_profile_wallet_ledger_source_type(snapshot.source_type), + source_type: map_runtime_profile_wallet_ledger_source_type_back(snapshot.source_type), created_at_micros: snapshot.created_at_micros, } } @@ -1699,7 +1737,9 @@ pub(crate) fn map_custom_world_draft_card_detail_section_snapshot( } } -pub(crate) fn map_big_fish_session_snapshot(snapshot: BigFishSessionSnapshot) -> BigFishSessionRecord { +pub(crate) fn map_big_fish_session_snapshot( + snapshot: BigFishSessionSnapshot, +) -> BigFishSessionRecord { BigFishSessionRecord { session_id: snapshot.session_id, current_turn: snapshot.current_turn, @@ -1770,7 +1810,9 @@ pub(crate) fn map_puzzle_anchor_item(snapshot: DomainPuzzleAnchorItem) -> Puzzle } } -pub(crate) fn map_puzzle_result_draft(snapshot: DomainPuzzleResultDraft) -> PuzzleResultDraftRecord { +pub(crate) fn map_puzzle_result_draft( + snapshot: DomainPuzzleResultDraft, +) -> PuzzleResultDraftRecord { PuzzleResultDraftRecord { level_name: snapshot.level_name, summary: snapshot.summary, @@ -1790,7 +1832,9 @@ pub(crate) fn map_puzzle_result_draft(snapshot: DomainPuzzleResultDraft) -> Puzz } } -pub(crate) fn map_puzzle_creator_intent(snapshot: DomainPuzzleCreatorIntent) -> PuzzleCreatorIntentRecord { +pub(crate) fn map_puzzle_creator_intent( + snapshot: DomainPuzzleCreatorIntent, +) -> PuzzleCreatorIntentRecord { PuzzleCreatorIntentRecord { source_mode: snapshot.source_mode, raw_messages_summary: snapshot.raw_messages_summary, @@ -1879,7 +1923,9 @@ pub(crate) fn map_puzzle_result_preview_finding( } } -pub(crate) fn map_puzzle_work_profile(snapshot: DomainPuzzleWorkProfile) -> PuzzleWorkProfileRecord { +pub(crate) fn map_puzzle_work_profile( + snapshot: DomainPuzzleWorkProfile, +) -> PuzzleWorkProfileRecord { PuzzleWorkProfileRecord { work_id: snapshot.work_id, profile_id: snapshot.profile_id, @@ -1977,7 +2023,9 @@ pub(crate) fn map_puzzle_merged_group_state( } } -pub(crate) fn map_puzzle_cell_position(snapshot: DomainPuzzleCellPosition) -> PuzzleCellPositionRecord { +pub(crate) fn map_puzzle_cell_position( + snapshot: DomainPuzzleCellPosition, +) -> PuzzleCellPositionRecord { PuzzleCellPositionRecord { row: snapshot.row, col: snapshot.col, @@ -2107,7 +2155,9 @@ pub(crate) fn map_big_fish_agent_message_snapshot( } } -pub(crate) fn map_big_fish_runtime_snapshot(snapshot: BigFishRuntimeSnapshot) -> BigFishRuntimeRecord { +pub(crate) fn map_big_fish_runtime_snapshot( + snapshot: BigFishRuntimeSnapshot, +) -> BigFishRuntimeRecord { BigFishRuntimeRecord { run_id: snapshot.run_id, session_id: snapshot.session_id, @@ -2254,7 +2304,9 @@ pub(crate) fn map_story_event_snapshot(snapshot: StoryEventSnapshot) -> StoryEve } } -pub(crate) fn map_battle_state_snapshot(snapshot: BattleStateSnapshot) -> DomainBattleStateSnapshot { +pub(crate) fn map_battle_state_snapshot( + snapshot: BattleStateSnapshot, +) -> DomainBattleStateSnapshot { DomainBattleStateSnapshot { battle_state_id: snapshot.battle_state_id, story_session_id: snapshot.story_session_id, @@ -2356,7 +2408,9 @@ pub(crate) fn map_inventory_slot_snapshot( } } -pub(crate) fn map_npc_interaction_result(result: NpcInteractionResult) -> DomainNpcInteractionResult { +pub(crate) fn map_npc_interaction_result( + result: NpcInteractionResult, +) -> DomainNpcInteractionResult { DomainNpcInteractionResult { npc_state: map_npc_state_snapshot(result.npc_state), interaction_status: map_npc_interaction_status(result.interaction_status), @@ -2414,7 +2468,9 @@ pub(crate) fn map_npc_stance_profile(value: NpcStanceProfile) -> DomainNpcStance } } -pub(crate) fn map_npc_interaction_status(value: NpcInteractionStatus) -> DomainNpcInteractionStatus { +pub(crate) fn map_npc_interaction_status( + value: NpcInteractionStatus, +) -> DomainNpcInteractionStatus { match value { NpcInteractionStatus::Previewed => DomainNpcInteractionStatus::Previewed, NpcInteractionStatus::Dialogue => DomainNpcInteractionStatus::Dialogue, @@ -2470,20 +2526,12 @@ pub(crate) fn map_access_policy_back( } } -pub(crate) fn map_runtime_platform_theme(value: RuntimePlatformTheme) -> RuntimePlatformTheme { +pub(crate) fn map_runtime_platform_theme( + value: DomainRuntimePlatformTheme, +) -> crate::module_bindings::RuntimePlatformTheme { match value { - RuntimePlatformTheme::Light => RuntimePlatformTheme::Light, - RuntimePlatformTheme::Dark => RuntimePlatformTheme::Dark, - } -} - -pub(crate) fn map_runtime_profile_wallet_ledger_source_type( - value: RuntimeProfileWalletLedgerSourceType, -) -> RuntimeProfileWalletLedgerSourceType { - match value { - RuntimeProfileWalletLedgerSourceType::SnapshotSync => { - RuntimeProfileWalletLedgerSourceType::SnapshotSync - } + DomainRuntimePlatformTheme::Light => crate::module_bindings::RuntimePlatformTheme::Light, + DomainRuntimePlatformTheme::Dark => crate::module_bindings::RuntimePlatformTheme::Dark, } } @@ -2495,9 +2543,7 @@ pub(crate) fn map_runtime_item_reward_item_rarity( DomainRuntimeItemRewardItemRarity::Uncommon => RuntimeItemRewardItemRarity::Uncommon, DomainRuntimeItemRewardItemRarity::Rare => RuntimeItemRewardItemRarity::Rare, DomainRuntimeItemRewardItemRarity::Epic => RuntimeItemRewardItemRarity::Epic, - DomainRuntimeItemRewardItemRarity::Legendary => { - RuntimeItemRewardItemRarity::Legendary - } + DomainRuntimeItemRewardItemRarity::Legendary => RuntimeItemRewardItemRarity::Legendary, } } @@ -2511,7 +2557,9 @@ pub(crate) fn map_runtime_item_equipment_slot( } } -pub(crate) fn map_custom_world_theme_mode(value: DomainCustomWorldThemeMode) -> CustomWorldThemeMode { +pub(crate) fn map_custom_world_theme_mode( + value: DomainCustomWorldThemeMode, +) -> CustomWorldThemeMode { match value { DomainCustomWorldThemeMode::Martial => CustomWorldThemeMode::Martial, DomainCustomWorldThemeMode::Arcane => CustomWorldThemeMode::Arcane, @@ -2529,10 +2577,12 @@ pub(crate) fn map_battle_mode(value: DomainBattleMode) -> BattleMode { } } -pub(crate) fn map_runtime_platform_theme_back(value: RuntimePlatformTheme) -> RuntimePlatformTheme { +pub(crate) fn map_runtime_platform_theme_back( + value: crate::module_bindings::RuntimePlatformTheme, +) -> DomainRuntimePlatformTheme { match value { - RuntimePlatformTheme::Light => RuntimePlatformTheme::Light, - RuntimePlatformTheme::Dark => RuntimePlatformTheme::Dark, + crate::module_bindings::RuntimePlatformTheme::Light => DomainRuntimePlatformTheme::Light, + crate::module_bindings::RuntimePlatformTheme::Dark => DomainRuntimePlatformTheme::Dark, } } @@ -2544,9 +2594,7 @@ pub(crate) fn map_runtime_item_reward_item_rarity_back( RuntimeItemRewardItemRarity::Uncommon => DomainRuntimeItemRewardItemRarity::Uncommon, RuntimeItemRewardItemRarity::Rare => DomainRuntimeItemRewardItemRarity::Rare, RuntimeItemRewardItemRarity::Epic => DomainRuntimeItemRewardItemRarity::Epic, - RuntimeItemRewardItemRarity::Legendary => { - DomainRuntimeItemRewardItemRarity::Legendary - } + RuntimeItemRewardItemRarity::Legendary => DomainRuntimeItemRewardItemRarity::Legendary, } } @@ -2573,7 +2621,9 @@ pub(crate) fn map_custom_world_theme_mode_back( } } -pub(crate) fn map_custom_world_publication_status(value: CustomWorldPublicationStatus) -> &'static str { +pub(crate) fn map_custom_world_publication_status( + value: CustomWorldPublicationStatus, +) -> &'static str { match value { CustomWorldPublicationStatus::Draft => "draft", CustomWorldPublicationStatus::Published => "published", @@ -2671,6 +2721,8 @@ pub(crate) fn format_rpg_agent_operation_type( crate::module_bindings::RpgAgentOperationType::ExpandLongTail => "expand_long_tail", crate::module_bindings::RpgAgentOperationType::PublishWorld => "publish_world", crate::module_bindings::RpgAgentOperationType::RevertCheckpoint => "revert_checkpoint", + crate::module_bindings::RpgAgentOperationType::DeleteCharacters => "delete_characters", + crate::module_bindings::RpgAgentOperationType::DeleteLandmarks => "delete_landmarks", } } @@ -2739,15 +2791,48 @@ pub(crate) fn format_custom_world_role_asset_status_back( .to_string() } -pub(crate) fn map_big_fish_asset_kind_input( +impl TryFrom<&str> for BigFishAssetKind { + type Error = SpacetimeClientError; + + fn try_from(value: &str) -> Result { + match value.trim() { + "level_main_image" => Ok(Self::LevelMainImage), + "level_motion" => Ok(Self::LevelMotion), + "stage_background" => Ok(Self::StageBackground), + other => Err(SpacetimeClientError::Runtime(format!( + "big fish asset kind `{other}` 当前尚未支持" + ))), + } + } +} + +pub(crate) fn map_big_fish_creation_stage( + value: module_big_fish::BigFishCreationStage, +) -> BigFishCreationStage { + match value { + module_big_fish::BigFishCreationStage::CollectingAnchors => { + BigFishCreationStage::CollectingAnchors + } + module_big_fish::BigFishCreationStage::DraftReady => BigFishCreationStage::DraftReady, + module_big_fish::BigFishCreationStage::AssetRefining => BigFishCreationStage::AssetRefining, + module_big_fish::BigFishCreationStage::ReadyToPublish => { + BigFishCreationStage::ReadyToPublish + } + module_big_fish::BigFishCreationStage::Published => BigFishCreationStage::Published, + } +} + +pub(crate) fn parse_big_fish_creation_stage( value: &str, -) -> Result { +) -> Result { match value.trim() { - "level_main_image" => Ok(BigFishAssetKind::LevelMainImage), - "level_motion" => Ok(BigFishAssetKind::LevelMotion), - "stage_background" => Ok(BigFishAssetKind::StageBackground), + "collecting_anchors" => Ok(BigFishCreationStage::CollectingAnchors), + "draft_ready" => Ok(BigFishCreationStage::DraftReady), + "asset_refining" => Ok(BigFishCreationStage::AssetRefining), + "ready_to_publish" => Ok(BigFishCreationStage::ReadyToPublish), + "published" => Ok(BigFishCreationStage::Published), other => Err(SpacetimeClientError::Runtime(format!( - "big fish asset kind `{other}` 当前尚未支持" + "big fish creation stage `{other}` ??????" ))), } } @@ -2830,15 +2915,37 @@ pub(crate) fn map_battle_mode_back(value: BattleMode) -> DomainBattleMode { } pub(crate) fn map_runtime_browse_history_theme_mode_back( - value: RuntimeBrowseHistoryThemeMode, -) -> RuntimeBrowseHistoryThemeMode { + value: crate::module_bindings::RuntimeBrowseHistoryThemeMode, +) -> module_runtime::RuntimeBrowseHistoryThemeMode { match value { - RuntimeBrowseHistoryThemeMode::Martial => RuntimeBrowseHistoryThemeMode::Martial, - RuntimeBrowseHistoryThemeMode::Arcane => RuntimeBrowseHistoryThemeMode::Arcane, - RuntimeBrowseHistoryThemeMode::Machina => RuntimeBrowseHistoryThemeMode::Machina, - RuntimeBrowseHistoryThemeMode::Tide => RuntimeBrowseHistoryThemeMode::Tide, - RuntimeBrowseHistoryThemeMode::Rift => RuntimeBrowseHistoryThemeMode::Rift, - RuntimeBrowseHistoryThemeMode::Mythic => RuntimeBrowseHistoryThemeMode::Mythic, + crate::module_bindings::RuntimeBrowseHistoryThemeMode::Martial => { + module_runtime::RuntimeBrowseHistoryThemeMode::Martial + } + crate::module_bindings::RuntimeBrowseHistoryThemeMode::Arcane => { + module_runtime::RuntimeBrowseHistoryThemeMode::Arcane + } + crate::module_bindings::RuntimeBrowseHistoryThemeMode::Machina => { + module_runtime::RuntimeBrowseHistoryThemeMode::Machina + } + crate::module_bindings::RuntimeBrowseHistoryThemeMode::Tide => { + module_runtime::RuntimeBrowseHistoryThemeMode::Tide + } + crate::module_bindings::RuntimeBrowseHistoryThemeMode::Rift => { + module_runtime::RuntimeBrowseHistoryThemeMode::Rift + } + crate::module_bindings::RuntimeBrowseHistoryThemeMode::Mythic => { + module_runtime::RuntimeBrowseHistoryThemeMode::Mythic + } + } +} + +pub(crate) fn map_runtime_profile_wallet_ledger_source_type_back( + value: crate::module_bindings::RuntimeProfileWalletLedgerSourceType, +) -> module_runtime::RuntimeProfileWalletLedgerSourceType { + match value { + crate::module_bindings::RuntimeProfileWalletLedgerSourceType::SnapshotSync => { + module_runtime::RuntimeProfileWalletLedgerSourceType::SnapshotSync + } } } @@ -2896,9 +3003,7 @@ pub(crate) fn map_ai_result_reference_kind( AiResultReferenceKind::CustomWorldProfile } DomainAiResultReferenceKind::QuestRecord => AiResultReferenceKind::QuestRecord, - DomainAiResultReferenceKind::RuntimeItemRecord => { - AiResultReferenceKind::RuntimeItemRecord - } + DomainAiResultReferenceKind::RuntimeItemRecord => AiResultReferenceKind::RuntimeItemRecord, DomainAiResultReferenceKind::AssetObject => AiResultReferenceKind::AssetObject, } } @@ -3001,7 +3106,10 @@ pub(crate) fn map_runtime_item_reward_item_snapshot_back( } } -pub(crate) fn parse_json_value(value: &str, label: &str) -> Result { +pub(crate) fn parse_json_value( + value: &str, + label: &str, +) -> Result { serde_json::from_str::(value) .map_err(|error| SpacetimeClientError::Runtime(format!("{label} 非法: {error}"))) } @@ -3029,7 +3137,10 @@ pub(crate) fn parse_json_array( } } -pub(crate) fn parse_json_string_array(value: &str, label: &str) -> Result, SpacetimeClientError> { +pub(crate) fn parse_json_string_array( + value: &str, + label: &str, +) -> Result, SpacetimeClientError> { parse_json_array(value, label)? .into_iter() .map(|entry| match entry { @@ -3907,6 +4018,19 @@ pub struct BigFishMessageSubmitRecordInput { pub submitted_at_micros: i64, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct BigFishMessageFinalizeRecordInput { + pub session_id: String, + pub owner_user_id: String, + pub assistant_message_id: Option, + pub assistant_reply_text: Option, + pub stage: String, + pub progress_percent: u32, + pub anchor_pack_json: String, + pub error_message: Option, + pub updated_at_micros: i64, +} + #[derive(Clone, Debug, PartialEq, Eq)] pub struct BigFishAssetGenerateRecordInput { pub session_id: String, @@ -4274,33 +4398,35 @@ pub(crate) fn build_resolve_combat_action_record( } } -pub(crate) fn map_resolve_npc_battle_interaction_input( - input: ResolveNpcBattleInteractionInput, -) -> ResolveNpcBattleInteractionInput { - ResolveNpcBattleInteractionInput { - npc_interaction: ResolveNpcInteractionInput { - runtime_session_id: input.npc_interaction.runtime_session_id, - npc_id: input.npc_interaction.npc_id, - npc_name: input.npc_interaction.npc_name, - interaction_function_id: input.npc_interaction.interaction_function_id, - release_npc_id: input.npc_interaction.release_npc_id, - updated_at_micros: input.npc_interaction.updated_at_micros, - }, - story_session_id: input.story_session_id, - actor_user_id: input.actor_user_id, - battle_state_id: input.battle_state_id, - player_hp: input.player_hp, - player_max_hp: input.player_max_hp, - player_mana: input.player_mana, - player_max_mana: input.player_max_mana, - target_hp: input.target_hp, - target_max_hp: input.target_max_hp, - experience_reward: input.experience_reward, - reward_items: input - .reward_items - .into_iter() - .map(map_runtime_item_reward_item_snapshot) - .collect(), +impl From + for crate::module_bindings::ResolveNpcBattleInteractionInput +{ + fn from(input: ResolveNpcBattleInteractionInput) -> Self { + Self { + npc_interaction: crate::module_bindings::ResolveNpcInteractionInput { + runtime_session_id: input.npc_interaction.runtime_session_id, + npc_id: input.npc_interaction.npc_id, + npc_name: input.npc_interaction.npc_name, + interaction_function_id: input.npc_interaction.interaction_function_id, + release_npc_id: input.npc_interaction.release_npc_id, + updated_at_micros: input.npc_interaction.updated_at_micros, + }, + story_session_id: input.story_session_id, + actor_user_id: input.actor_user_id, + battle_state_id: input.battle_state_id, + player_hp: input.player_hp, + player_max_hp: input.player_max_hp, + player_mana: input.player_mana, + player_max_mana: input.player_max_mana, + target_hp: input.target_hp, + target_max_hp: input.target_max_hp, + experience_reward: input.experience_reward, + reward_items: input + .reward_items + .into_iter() + .map(map_runtime_item_reward_item_snapshot) + .collect(), + } } } @@ -4369,7 +4495,9 @@ pub(crate) fn build_npc_state_record(snapshot: DomainNpcStateSnapshot) -> NpcSta } } -pub(crate) fn build_npc_interaction_record(result: DomainNpcInteractionResult) -> NpcInteractionRecord { +pub(crate) fn build_npc_interaction_record( + result: DomainNpcInteractionResult, +) -> NpcInteractionRecord { NpcInteractionRecord { npc_state: build_npc_state_record(result.npc_state), interaction_status: format_npc_interaction_status(result.interaction_status).to_string(), @@ -4416,7 +4544,9 @@ pub(crate) fn format_npc_interaction_status(value: DomainNpcInteractionStatus) - } } -pub(crate) fn format_npc_interaction_battle_mode(value: DomainNpcInteractionBattleMode) -> &'static str { +pub(crate) fn format_npc_interaction_battle_mode( + value: DomainNpcInteractionBattleMode, +) -> &'static str { match value { DomainNpcInteractionBattleMode::Fight => "fight", DomainNpcInteractionBattleMode::Spar => "spar", @@ -4427,12 +4557,8 @@ pub(crate) fn map_inventory_container_kind( value: InventoryContainerKind, ) -> module_inventory::InventoryContainerKind { match value { - InventoryContainerKind::Backpack => { - module_inventory::InventoryContainerKind::Backpack - } - InventoryContainerKind::Equipment => { - module_inventory::InventoryContainerKind::Equipment - } + InventoryContainerKind::Backpack => module_inventory::InventoryContainerKind::Backpack, + InventoryContainerKind::Equipment => module_inventory::InventoryContainerKind::Equipment, } } @@ -4471,12 +4597,8 @@ pub(crate) fn map_inventory_item_source_kind( InventoryItemSourceKind::TreasureReward => { module_inventory::InventoryItemSourceKind::TreasureReward } - InventoryItemSourceKind::NpcGift => { - module_inventory::InventoryItemSourceKind::NpcGift - } - InventoryItemSourceKind::NpcTrade => { - module_inventory::InventoryItemSourceKind::NpcTrade - } + InventoryItemSourceKind::NpcGift => module_inventory::InventoryItemSourceKind::NpcGift, + InventoryItemSourceKind::NpcTrade => module_inventory::InventoryItemSourceKind::NpcTrade, InventoryItemSourceKind::CombatDrop => { module_inventory::InventoryItemSourceKind::CombatDrop } @@ -4491,4 +4613,3 @@ pub(crate) fn map_inventory_item_source_kind( } } } - diff --git a/server-rs/crates/spacetime-client/src/module_bindings/auth_identity_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/auth_identity_table.rs new file mode 100644 index 00000000..07644b31 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/auth_identity_table.rs @@ -0,0 +1,163 @@ +// 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_identity_type::AuthIdentity; + +/// Table handle for the table `auth_identity`. +/// +/// Obtain a handle from the [`AuthIdentityTableAccess::auth_identity`] method on [`super::RemoteTables`], +/// like `ctx.db.auth_identity()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.auth_identity().on_insert(...)`. +pub struct AuthIdentityTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `auth_identity`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait AuthIdentityTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`AuthIdentityTableHandle`], which mediates access to the table `auth_identity`. + fn auth_identity(&self) -> AuthIdentityTableHandle<'_>; +} + +impl AuthIdentityTableAccess for super::RemoteTables { + fn auth_identity(&self) -> AuthIdentityTableHandle<'_> { + AuthIdentityTableHandle { + imp: self.imp.get_table::("auth_identity"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct AuthIdentityInsertCallbackId(__sdk::CallbackId); +pub struct AuthIdentityDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for AuthIdentityTableHandle<'ctx> { + type Row = AuthIdentity; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { self.imp.count() } + fn iter(&self) -> impl Iterator + '_ { self.imp.iter() } + + type InsertCallbackId = AuthIdentityInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> AuthIdentityInsertCallbackId { + AuthIdentityInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: AuthIdentityInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = AuthIdentityDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> AuthIdentityDeleteCallbackId { + AuthIdentityDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: AuthIdentityDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +pub struct AuthIdentityUpdateCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::TableWithPrimaryKey for AuthIdentityTableHandle<'ctx> { + type UpdateCallbackId = AuthIdentityUpdateCallbackId; + + fn on_update( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, + ) -> AuthIdentityUpdateCallbackId { + AuthIdentityUpdateCallbackId(self.imp.on_update(Box::new(callback))) + } + + fn remove_on_update(&self, callback: AuthIdentityUpdateCallbackId) { + self.imp.remove_on_update(callback.0) + } +} + + /// Access to the `identity_id` unique index on the table `auth_identity`, + /// which allows point queries on the field of the same name + /// via the [`AuthIdentityIdentityIdUnique::find`] method. + /// + /// Users are encouraged not to explicitly reference this type, + /// but to directly chain method calls, + /// like `ctx.db.auth_identity().identity_id().find(...)`. + pub struct AuthIdentityIdentityIdUnique<'ctx> { + imp: __sdk::UniqueConstraintHandle, + phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, + } + + impl<'ctx> AuthIdentityTableHandle<'ctx> { + /// Get a handle on the `identity_id` unique index on the table `auth_identity`. + pub fn identity_id(&self) -> AuthIdentityIdentityIdUnique<'ctx> { + AuthIdentityIdentityIdUnique { + imp: self.imp.get_unique_constraint::("identity_id"), + phantom: std::marker::PhantomData, + } + } + } + + impl<'ctx> AuthIdentityIdentityIdUnique<'ctx> { + /// Find the subscribed row whose `identity_id` column value is equal to `col_val`, + /// if such a row is present in the client cache. + pub fn find(&self, col_val: &String) -> Option { + self.imp.find(col_val) + } + } + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + + let _table = client_cache.get_or_make_table::("auth_identity"); + _table.add_unique_constraint::("identity_id", |row| &row.identity_id); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::v2::TableUpdate, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse( + "TableUpdate", + "TableUpdate", + ).with_cause(e).into() + }) +} + + #[allow(non_camel_case_types)] + /// Extension trait for query builder access to the table `AuthIdentity`. + /// + /// Implemented for [`__sdk::QueryTableAccessor`]. + pub trait auth_identityQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `AuthIdentity`. + fn auth_identity(&self) -> __sdk::__query_builder::Table; + } + + impl auth_identityQueryTableAccess for __sdk::QueryTableAccessor { + fn auth_identity(&self) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("auth_identity") + } + } + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/auth_identity_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/auth_identity_type.rs new file mode 100644 index 00000000..27a33d40 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/auth_identity_type.rs @@ -0,0 +1,83 @@ +// 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 AuthIdentity { + pub identity_id: String, + pub user_id: String, + pub provider: String, + pub provider_uid: String, + pub provider_union_id: Option::, + pub phone_e_164: Option::, + pub display_name: Option::, + pub avatar_url: Option::, +} + + +impl __sdk::InModule for AuthIdentity { + type Module = super::RemoteModule; +} + + +/// Column accessor struct for the table `AuthIdentity`. +/// +/// Provides typed access to columns for query building. +pub struct AuthIdentityCols { + pub identity_id: __sdk::__query_builder::Col, + pub user_id: __sdk::__query_builder::Col, + pub provider: __sdk::__query_builder::Col, + pub provider_uid: __sdk::__query_builder::Col, + pub provider_union_id: __sdk::__query_builder::Col>, + pub phone_e_164: __sdk::__query_builder::Col>, + pub display_name: __sdk::__query_builder::Col>, + pub avatar_url: __sdk::__query_builder::Col>, +} + +impl __sdk::__query_builder::HasCols for AuthIdentity { + type Cols = AuthIdentityCols; + fn cols(table_name: &'static str) -> Self::Cols { + AuthIdentityCols { + identity_id: __sdk::__query_builder::Col::new(table_name, "identity_id"), + user_id: __sdk::__query_builder::Col::new(table_name, "user_id"), + provider: __sdk::__query_builder::Col::new(table_name, "provider"), + provider_uid: __sdk::__query_builder::Col::new(table_name, "provider_uid"), + provider_union_id: __sdk::__query_builder::Col::new(table_name, "provider_union_id"), + phone_e_164: __sdk::__query_builder::Col::new(table_name, "phone_e_164"), + display_name: __sdk::__query_builder::Col::new(table_name, "display_name"), + avatar_url: __sdk::__query_builder::Col::new(table_name, "avatar_url"), + + } + } +} + +/// Indexed column accessor struct for the table `AuthIdentity`. +/// +/// Provides typed access to indexed columns for query building. +pub struct AuthIdentityIxCols { + pub identity_id: __sdk::__query_builder::IxCol, + pub user_id: __sdk::__query_builder::IxCol, +} + +impl __sdk::__query_builder::HasIxCols for AuthIdentity { + type IxCols = AuthIdentityIxCols; + fn ix_cols(table_name: &'static str) -> Self::IxCols { + AuthIdentityIxCols { + identity_id: __sdk::__query_builder::IxCol::new(table_name, "identity_id"), + user_id: __sdk::__query_builder::IxCol::new(table_name, "user_id"), + + } + } +} + +impl __sdk::__query_builder::CanBeLookupTable for AuthIdentity {} + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/auth_store_snapshot_import_procedure_result_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/auth_store_snapshot_import_procedure_result_type.rs new file mode 100644 index 00000000..5ab89cf2 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/auth_store_snapshot_import_procedure_result_type.rs @@ -0,0 +1,26 @@ +// 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_snapshot_import_record_type::AuthStoreSnapshotImportRecord; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct AuthStoreSnapshotImportProcedureResult { + pub ok: bool, + pub record: Option::, + pub error_message: Option::, +} + + +impl __sdk::InModule for AuthStoreSnapshotImportProcedureResult { + type Module = super::RemoteModule; +} + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/auth_store_snapshot_import_record_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/auth_store_snapshot_import_record_type.rs new file mode 100644 index 00000000..80effd2b --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/auth_store_snapshot_import_record_type.rs @@ -0,0 +1,25 @@ +// 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 AuthStoreSnapshotImportRecord { + pub imported_user_count: u32, + pub imported_identity_count: u32, + pub imported_refresh_session_count: u32, +} + + +impl __sdk::InModule for AuthStoreSnapshotImportRecord { + type Module = super::RemoteModule; +} + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_snapshot_from_tables_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_snapshot_from_tables_procedure.rs new file mode 100644 index 00000000..2e273a5e --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/export_auth_store_snapshot_from_tables_procedure.rs @@ -0,0 +1,53 @@ +// 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_snapshot_procedure_result_type::AuthStoreSnapshotProcedureResult; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] + struct ExportAuthStoreSnapshotFromTablesArgs { + } + + +impl __sdk::InModule for ExportAuthStoreSnapshotFromTablesArgs { + type Module = super::RemoteModule; +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the procedure `export_auth_store_snapshot_from_tables`. +/// +/// Implemented for [`super::RemoteProcedures`]. +pub trait export_auth_store_snapshot_from_tables { + fn export_auth_store_snapshot_from_tables(&self, ) { + self.export_auth_store_snapshot_from_tables_then( |_, _| {}); + } + + fn export_auth_store_snapshot_from_tables_then( + &self, + + __callback: impl FnOnce(&super::ProcedureEventContext, Result) + Send + 'static, + ); +} + +impl export_auth_store_snapshot_from_tables for super::RemoteProcedures { + fn export_auth_store_snapshot_from_tables_then( + &self, + + __callback: impl FnOnce(&super::ProcedureEventContext, Result) + Send + 'static, + ) { + self.imp.invoke_procedure_with_callback::<_, AuthStoreSnapshotProcedureResult>( + "export_auth_store_snapshot_from_tables", + ExportAuthStoreSnapshotFromTablesArgs { }, + __callback, + ); + } +} + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/import_auth_store_snapshot_procedure.rs b/server-rs/crates/spacetime-client/src/module_bindings/import_auth_store_snapshot_procedure.rs new file mode 100644 index 00000000..656b962b --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/import_auth_store_snapshot_procedure.rs @@ -0,0 +1,53 @@ +// 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_snapshot_import_procedure_result_type::AuthStoreSnapshotImportProcedureResult; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] + struct ImportAuthStoreSnapshotArgs { + } + + +impl __sdk::InModule for ImportAuthStoreSnapshotArgs { + type Module = super::RemoteModule; +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the procedure `import_auth_store_snapshot`. +/// +/// Implemented for [`super::RemoteProcedures`]. +pub trait import_auth_store_snapshot { + fn import_auth_store_snapshot(&self, ) { + self.import_auth_store_snapshot_then( |_, _| {}); + } + + fn import_auth_store_snapshot_then( + &self, + + __callback: impl FnOnce(&super::ProcedureEventContext, Result) + Send + 'static, + ); +} + +impl import_auth_store_snapshot for super::RemoteProcedures { + fn import_auth_store_snapshot_then( + &self, + + __callback: impl FnOnce(&super::ProcedureEventContext, Result) + Send + 'static, + ) { + self.imp.invoke_procedure_with_callback::<_, AuthStoreSnapshotImportProcedureResult>( + "import_auth_store_snapshot", + ImportAuthStoreSnapshotArgs { }, + __callback, + ); + } +} + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/mod.rs b/server-rs/crates/spacetime-client/src/module_bindings/mod.rs index 967cae67..a26b146b 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/mod.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/mod.rs @@ -44,13 +44,13 @@ pub mod asset_object_access_policy_type; pub mod asset_object_procedure_result_type; pub mod asset_object_upsert_input_type; pub mod asset_object_upsert_snapshot_type; -<<<<<<< HEAD -======= +pub mod auth_identity_type; pub mod auth_store_snapshot_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_upsert_input_type; ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) pub mod battle_mode_type; pub mod battle_state_type; pub mod battle_state_input_type; @@ -245,6 +245,7 @@ pub mod quest_status_type; pub mod quest_step_snapshot_type; pub mod quest_treasure_inspected_signal_type; pub mod quest_turn_in_input_type; +pub mod refresh_session_type; pub mod resolve_combat_action_input_type; pub mod resolve_combat_action_procedure_result_type; pub mod resolve_combat_action_result_type; @@ -315,6 +316,7 @@ pub mod treasure_record_procedure_result_type; pub mod treasure_record_snapshot_type; pub mod treasure_resolve_input_type; pub mod unequip_inventory_item_input_type; +pub mod user_account_type; pub mod user_browse_history_type; pub mod accept_quest_reducer; pub mod acknowledge_quest_completion_reducer; @@ -346,10 +348,8 @@ pub mod ai_task_stage_table; pub mod ai_text_chunk_table; pub mod asset_entity_binding_table; pub mod asset_object_table; -<<<<<<< HEAD -======= +pub mod auth_identity_table; pub mod auth_store_snapshot_table; ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) pub mod battle_state_table; pub mod big_fish_agent_message_table; pub mod big_fish_asset_slot_table; @@ -376,11 +376,13 @@ pub mod puzzle_runtime_run_table; pub mod puzzle_work_profile_table; pub mod quest_log_table; pub mod quest_record_table; +pub mod refresh_session_table; pub mod runtime_setting_table; pub mod runtime_snapshot_table; pub mod story_event_table; pub mod story_session_table; pub mod treasure_record_table; +pub mod user_account_table; pub mod user_browse_history_table; pub mod advance_puzzle_next_level_procedure; pub mod append_ai_text_chunk_and_return_procedure; @@ -406,18 +408,13 @@ pub mod delete_custom_world_profile_and_return_procedure; pub mod delete_runtime_snapshot_and_return_procedure; pub mod drag_puzzle_piece_or_group_procedure; pub mod execute_custom_world_agent_action_procedure; +pub mod export_auth_store_snapshot_from_tables_procedure; pub mod fail_ai_task_and_return_procedure; -<<<<<<< HEAD pub mod finalize_big_fish_agent_message_turn_procedure; pub mod finalize_custom_world_agent_message_turn_procedure; pub mod finalize_puzzle_agent_message_turn_procedure; pub mod generate_big_fish_asset_procedure; -======= -pub mod finalize_custom_world_agent_message_turn_procedure; -pub mod finalize_puzzle_agent_message_turn_procedure; -pub mod generate_big_fish_asset_procedure; pub mod get_auth_store_snapshot_procedure; ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) pub mod get_battle_state_procedure; pub mod get_big_fish_run_procedure; pub mod get_big_fish_session_procedure; @@ -440,6 +437,7 @@ pub mod get_runtime_setting_or_default_procedure; pub mod get_runtime_snapshot_procedure; pub mod get_story_session_state_procedure; pub mod grant_player_progression_experience_and_return_procedure; +pub mod import_auth_store_snapshot_procedure; pub mod list_big_fish_works_procedure; pub mod list_custom_world_gallery_entries_procedure; pub mod list_custom_world_profiles_procedure; @@ -511,13 +509,13 @@ pub use asset_object_access_policy_type::AssetObjectAccessPolicy; pub use asset_object_procedure_result_type::AssetObjectProcedureResult; pub use asset_object_upsert_input_type::AssetObjectUpsertInput; pub use asset_object_upsert_snapshot_type::AssetObjectUpsertSnapshot; -<<<<<<< HEAD -======= +pub use auth_identity_type::AuthIdentity; pub use auth_store_snapshot_type::AuthStoreSnapshot; +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_upsert_input_type::AuthStoreSnapshotUpsertInput; ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) pub use battle_mode_type::BattleMode; pub use battle_state_type::BattleState; pub use battle_state_input_type::BattleStateInput; @@ -712,6 +710,7 @@ pub use quest_status_type::QuestStatus; pub use quest_step_snapshot_type::QuestStepSnapshot; pub use quest_treasure_inspected_signal_type::QuestTreasureInspectedSignal; pub use quest_turn_in_input_type::QuestTurnInInput; +pub use refresh_session_type::RefreshSession; pub use resolve_combat_action_input_type::ResolveCombatActionInput; pub use resolve_combat_action_procedure_result_type::ResolveCombatActionProcedureResult; pub use resolve_combat_action_result_type::ResolveCombatActionResult; @@ -782,6 +781,7 @@ pub use treasure_record_procedure_result_type::TreasureRecordProcedureResult; pub use treasure_record_snapshot_type::TreasureRecordSnapshot; pub use treasure_resolve_input_type::TreasureResolveInput; pub use unequip_inventory_item_input_type::UnequipInventoryItemInput; +pub use user_account_type::UserAccount; pub use user_browse_history_type::UserBrowseHistory; pub use ai_result_reference_table::*; pub use ai_task_table::*; @@ -789,10 +789,8 @@ pub use ai_task_stage_table::*; pub use ai_text_chunk_table::*; pub use asset_entity_binding_table::*; pub use asset_object_table::*; -<<<<<<< HEAD -======= +pub use auth_identity_table::*; pub use auth_store_snapshot_table::*; ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) pub use battle_state_table::*; pub use big_fish_agent_message_table::*; pub use big_fish_asset_slot_table::*; @@ -819,11 +817,13 @@ pub use puzzle_runtime_run_table::*; pub use puzzle_work_profile_table::*; pub use quest_log_table::*; pub use quest_record_table::*; +pub use refresh_session_table::*; pub use runtime_setting_table::*; pub use runtime_snapshot_table::*; pub use story_event_table::*; pub use story_session_table::*; pub use treasure_record_table::*; +pub use user_account_table::*; pub use user_browse_history_table::*; pub use accept_quest_reducer::accept_quest; pub use acknowledge_quest_completion_reducer::acknowledge_quest_completion; @@ -873,18 +873,13 @@ pub use delete_custom_world_profile_and_return_procedure::delete_custom_world_pr pub use delete_runtime_snapshot_and_return_procedure::delete_runtime_snapshot_and_return; pub use drag_puzzle_piece_or_group_procedure::drag_puzzle_piece_or_group; 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 fail_ai_task_and_return_procedure::fail_ai_task_and_return; -<<<<<<< HEAD pub use finalize_big_fish_agent_message_turn_procedure::finalize_big_fish_agent_message_turn; pub use finalize_custom_world_agent_message_turn_procedure::finalize_custom_world_agent_message_turn; pub use finalize_puzzle_agent_message_turn_procedure::finalize_puzzle_agent_message_turn; pub use generate_big_fish_asset_procedure::generate_big_fish_asset; -======= -pub use finalize_custom_world_agent_message_turn_procedure::finalize_custom_world_agent_message_turn; -pub use finalize_puzzle_agent_message_turn_procedure::finalize_puzzle_agent_message_turn; -pub use generate_big_fish_asset_procedure::generate_big_fish_asset; pub use get_auth_store_snapshot_procedure::get_auth_store_snapshot; ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) pub use get_battle_state_procedure::get_battle_state; pub use get_big_fish_run_procedure::get_big_fish_run; pub use get_big_fish_session_procedure::get_big_fish_session; @@ -907,6 +902,7 @@ pub use get_runtime_setting_or_default_procedure::get_runtime_setting_or_default pub use get_runtime_snapshot_procedure::get_runtime_snapshot; pub use get_story_session_state_procedure::get_story_session_state; pub use grant_player_progression_experience_and_return_procedure::grant_player_progression_experience_and_return; +pub use import_auth_store_snapshot_procedure::import_auth_store_snapshot; pub use list_big_fish_works_procedure::list_big_fish_works; pub use list_custom_world_gallery_entries_procedure::list_custom_world_gallery_entries; pub use list_custom_world_profiles_procedure::list_custom_world_profiles; @@ -1200,6 +1196,7 @@ pub struct DbUpdate { ai_text_chunk: __sdk::TableUpdate, asset_entity_binding: __sdk::TableUpdate, asset_object: __sdk::TableUpdate, + auth_identity: __sdk::TableUpdate, auth_store_snapshot: __sdk::TableUpdate, battle_state: __sdk::TableUpdate, big_fish_agent_message: __sdk::TableUpdate, @@ -1227,11 +1224,13 @@ pub struct DbUpdate { puzzle_work_profile: __sdk::TableUpdate, quest_log: __sdk::TableUpdate, quest_record: __sdk::TableUpdate, + refresh_session: __sdk::TableUpdate, runtime_setting: __sdk::TableUpdate, runtime_snapshot: __sdk::TableUpdate, story_event: __sdk::TableUpdate, story_session: __sdk::TableUpdate, treasure_record: __sdk::TableUpdate, + user_account: __sdk::TableUpdate, user_browse_history: __sdk::TableUpdate, } @@ -1249,10 +1248,8 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "ai_text_chunk" => db_update.ai_text_chunk.append(ai_text_chunk_table::parse_table_update(table_update)?), "asset_entity_binding" => db_update.asset_entity_binding.append(asset_entity_binding_table::parse_table_update(table_update)?), "asset_object" => db_update.asset_object.append(asset_object_table::parse_table_update(table_update)?), -<<<<<<< HEAD -======= + "auth_identity" => db_update.auth_identity.append(auth_identity_table::parse_table_update(table_update)?), "auth_store_snapshot" => db_update.auth_store_snapshot.append(auth_store_snapshot_table::parse_table_update(table_update)?), ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) "battle_state" => db_update.battle_state.append(battle_state_table::parse_table_update(table_update)?), "big_fish_agent_message" => db_update.big_fish_agent_message.append(big_fish_agent_message_table::parse_table_update(table_update)?), "big_fish_asset_slot" => db_update.big_fish_asset_slot.append(big_fish_asset_slot_table::parse_table_update(table_update)?), @@ -1279,11 +1276,13 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "puzzle_work_profile" => db_update.puzzle_work_profile.append(puzzle_work_profile_table::parse_table_update(table_update)?), "quest_log" => db_update.quest_log.append(quest_log_table::parse_table_update(table_update)?), "quest_record" => db_update.quest_record.append(quest_record_table::parse_table_update(table_update)?), + "refresh_session" => db_update.refresh_session.append(refresh_session_table::parse_table_update(table_update)?), "runtime_setting" => db_update.runtime_setting.append(runtime_setting_table::parse_table_update(table_update)?), "runtime_snapshot" => db_update.runtime_snapshot.append(runtime_snapshot_table::parse_table_update(table_update)?), "story_event" => db_update.story_event.append(story_event_table::parse_table_update(table_update)?), "story_session" => db_update.story_session.append(story_session_table::parse_table_update(table_update)?), "treasure_record" => db_update.treasure_record.append(treasure_record_table::parse_table_update(table_update)?), + "user_account" => db_update.user_account.append(user_account_table::parse_table_update(table_update)?), "user_browse_history" => db_update.user_browse_history.append(user_browse_history_table::parse_table_update(table_update)?), unknown => { @@ -1313,10 +1312,8 @@ impl __sdk::DbUpdate for DbUpdate { diff.ai_text_chunk = cache.apply_diff_to_table::("ai_text_chunk", &self.ai_text_chunk).with_updates_by_pk(|row| &row.text_chunk_row_id); diff.asset_entity_binding = cache.apply_diff_to_table::("asset_entity_binding", &self.asset_entity_binding).with_updates_by_pk(|row| &row.binding_id); diff.asset_object = cache.apply_diff_to_table::("asset_object", &self.asset_object).with_updates_by_pk(|row| &row.asset_object_id); -<<<<<<< HEAD -======= + diff.auth_identity = cache.apply_diff_to_table::("auth_identity", &self.auth_identity).with_updates_by_pk(|row| &row.identity_id); diff.auth_store_snapshot = cache.apply_diff_to_table::("auth_store_snapshot", &self.auth_store_snapshot).with_updates_by_pk(|row| &row.snapshot_id); ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) diff.battle_state = cache.apply_diff_to_table::("battle_state", &self.battle_state).with_updates_by_pk(|row| &row.battle_state_id); diff.big_fish_agent_message = cache.apply_diff_to_table::("big_fish_agent_message", &self.big_fish_agent_message).with_updates_by_pk(|row| &row.message_id); diff.big_fish_asset_slot = cache.apply_diff_to_table::("big_fish_asset_slot", &self.big_fish_asset_slot).with_updates_by_pk(|row| &row.slot_id); @@ -1343,11 +1340,13 @@ impl __sdk::DbUpdate for DbUpdate { diff.puzzle_work_profile = cache.apply_diff_to_table::("puzzle_work_profile", &self.puzzle_work_profile).with_updates_by_pk(|row| &row.profile_id); diff.quest_log = cache.apply_diff_to_table::("quest_log", &self.quest_log).with_updates_by_pk(|row| &row.log_id); diff.quest_record = cache.apply_diff_to_table::("quest_record", &self.quest_record).with_updates_by_pk(|row| &row.quest_id); + diff.refresh_session = cache.apply_diff_to_table::("refresh_session", &self.refresh_session).with_updates_by_pk(|row| &row.session_id); diff.runtime_setting = cache.apply_diff_to_table::("runtime_setting", &self.runtime_setting).with_updates_by_pk(|row| &row.user_id); diff.runtime_snapshot = cache.apply_diff_to_table::("runtime_snapshot", &self.runtime_snapshot).with_updates_by_pk(|row| &row.user_id); diff.story_event = cache.apply_diff_to_table::("story_event", &self.story_event).with_updates_by_pk(|row| &row.event_id); diff.story_session = cache.apply_diff_to_table::("story_session", &self.story_session).with_updates_by_pk(|row| &row.story_session_id); diff.treasure_record = cache.apply_diff_to_table::("treasure_record", &self.treasure_record).with_updates_by_pk(|row| &row.treasure_record_id); + diff.user_account = cache.apply_diff_to_table::("user_account", &self.user_account).with_updates_by_pk(|row| &row.user_id); diff.user_browse_history = cache.apply_diff_to_table::("user_browse_history", &self.user_browse_history).with_updates_by_pk(|row| &row.browse_history_id); diff @@ -1362,10 +1361,8 @@ for table_rows in raw.tables { "ai_text_chunk" => db_update.ai_text_chunk.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "asset_entity_binding" => db_update.asset_entity_binding.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "asset_object" => db_update.asset_object.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), -<<<<<<< HEAD -======= + "auth_identity" => db_update.auth_identity.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)?), ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) "battle_state" => db_update.battle_state.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "big_fish_agent_message" => db_update.big_fish_agent_message.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "big_fish_asset_slot" => db_update.big_fish_asset_slot.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -1392,11 +1389,13 @@ for table_rows in raw.tables { "puzzle_work_profile" => db_update.puzzle_work_profile.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "quest_log" => db_update.quest_log.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "quest_record" => db_update.quest_record.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), + "refresh_session" => db_update.refresh_session.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "runtime_setting" => db_update.runtime_setting.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "runtime_snapshot" => db_update.runtime_snapshot.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "story_event" => db_update.story_event.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "story_session" => db_update.story_session.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "treasure_record" => db_update.treasure_record.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), + "user_account" => db_update.user_account.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "user_browse_history" => db_update.user_browse_history.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), unknown => { return Err(__sdk::InternalError::unknown_name("table", unknown, "QueryRows").into()); } }} Ok(db_update) @@ -1411,10 +1410,8 @@ for table_rows in raw.tables { "ai_text_chunk" => db_update.ai_text_chunk.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "asset_entity_binding" => db_update.asset_entity_binding.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "asset_object" => db_update.asset_object.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), -<<<<<<< HEAD -======= + "auth_identity" => db_update.auth_identity.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)?), ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) "battle_state" => db_update.battle_state.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "big_fish_agent_message" => db_update.big_fish_agent_message.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "big_fish_asset_slot" => db_update.big_fish_asset_slot.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -1441,11 +1438,13 @@ for table_rows in raw.tables { "puzzle_work_profile" => db_update.puzzle_work_profile.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "quest_log" => db_update.quest_log.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "quest_record" => db_update.quest_record.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), + "refresh_session" => db_update.refresh_session.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "runtime_setting" => db_update.runtime_setting.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "runtime_snapshot" => db_update.runtime_snapshot.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "story_event" => db_update.story_event.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "story_session" => db_update.story_session.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "treasure_record" => db_update.treasure_record.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), + "user_account" => db_update.user_account.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "user_browse_history" => db_update.user_browse_history.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), unknown => { return Err(__sdk::InternalError::unknown_name("table", unknown, "QueryRows").into()); } }} Ok(db_update) @@ -1462,6 +1461,7 @@ pub struct AppliedDiff<'r> { ai_text_chunk: __sdk::TableAppliedDiff<'r, AiTextChunk>, asset_entity_binding: __sdk::TableAppliedDiff<'r, AssetEntityBinding>, asset_object: __sdk::TableAppliedDiff<'r, AssetObject>, + auth_identity: __sdk::TableAppliedDiff<'r, AuthIdentity>, auth_store_snapshot: __sdk::TableAppliedDiff<'r, AuthStoreSnapshot>, battle_state: __sdk::TableAppliedDiff<'r, BattleState>, big_fish_agent_message: __sdk::TableAppliedDiff<'r, BigFishAgentMessage>, @@ -1489,11 +1489,13 @@ pub struct AppliedDiff<'r> { puzzle_work_profile: __sdk::TableAppliedDiff<'r, PuzzleWorkProfileRow>, quest_log: __sdk::TableAppliedDiff<'r, QuestLog>, quest_record: __sdk::TableAppliedDiff<'r, QuestRecord>, + refresh_session: __sdk::TableAppliedDiff<'r, RefreshSession>, runtime_setting: __sdk::TableAppliedDiff<'r, RuntimeSetting>, runtime_snapshot: __sdk::TableAppliedDiff<'r, RuntimeSnapshotRow>, story_event: __sdk::TableAppliedDiff<'r, StoryEvent>, story_session: __sdk::TableAppliedDiff<'r, StorySession>, treasure_record: __sdk::TableAppliedDiff<'r, TreasureRecord>, + user_account: __sdk::TableAppliedDiff<'r, UserAccount>, user_browse_history: __sdk::TableAppliedDiff<'r, UserBrowseHistory>, __unused: std::marker::PhantomData<&'r ()>, } @@ -1511,10 +1513,8 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { callbacks.invoke_table_row_callbacks::("ai_text_chunk", &self.ai_text_chunk, event); callbacks.invoke_table_row_callbacks::("asset_entity_binding", &self.asset_entity_binding, event); callbacks.invoke_table_row_callbacks::("asset_object", &self.asset_object, event); -<<<<<<< HEAD -======= + callbacks.invoke_table_row_callbacks::("auth_identity", &self.auth_identity, event); callbacks.invoke_table_row_callbacks::("auth_store_snapshot", &self.auth_store_snapshot, event); ->>>>>>> 4f272a50 (迁移后端认证与拆分 Spacetime 客户端) callbacks.invoke_table_row_callbacks::("battle_state", &self.battle_state, event); callbacks.invoke_table_row_callbacks::("big_fish_agent_message", &self.big_fish_agent_message, event); callbacks.invoke_table_row_callbacks::("big_fish_asset_slot", &self.big_fish_asset_slot, event); @@ -1541,11 +1541,13 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { callbacks.invoke_table_row_callbacks::("puzzle_work_profile", &self.puzzle_work_profile, event); callbacks.invoke_table_row_callbacks::("quest_log", &self.quest_log, event); callbacks.invoke_table_row_callbacks::("quest_record", &self.quest_record, event); + callbacks.invoke_table_row_callbacks::("refresh_session", &self.refresh_session, event); callbacks.invoke_table_row_callbacks::("runtime_setting", &self.runtime_setting, event); callbacks.invoke_table_row_callbacks::("runtime_snapshot", &self.runtime_snapshot, event); callbacks.invoke_table_row_callbacks::("story_event", &self.story_event, event); callbacks.invoke_table_row_callbacks::("story_session", &self.story_session, event); callbacks.invoke_table_row_callbacks::("treasure_record", &self.treasure_record, event); + callbacks.invoke_table_row_callbacks::("user_account", &self.user_account, event); callbacks.invoke_table_row_callbacks::("user_browse_history", &self.user_browse_history, event); } } @@ -2204,6 +2206,7 @@ fn register_tables(client_cache: &mut __sdk::ClientCache) { ai_text_chunk_table::register_table(client_cache); asset_entity_binding_table::register_table(client_cache); asset_object_table::register_table(client_cache); + auth_identity_table::register_table(client_cache); auth_store_snapshot_table::register_table(client_cache); battle_state_table::register_table(client_cache); big_fish_agent_message_table::register_table(client_cache); @@ -2231,11 +2234,13 @@ fn register_tables(client_cache: &mut __sdk::ClientCache) { puzzle_work_profile_table::register_table(client_cache); quest_log_table::register_table(client_cache); quest_record_table::register_table(client_cache); + refresh_session_table::register_table(client_cache); runtime_setting_table::register_table(client_cache); runtime_snapshot_table::register_table(client_cache); story_event_table::register_table(client_cache); story_session_table::register_table(client_cache); treasure_record_table::register_table(client_cache); + user_account_table::register_table(client_cache); user_browse_history_table::register_table(client_cache); } const ALL_TABLE_NAMES: &'static [&'static str] = &[ @@ -2245,6 +2250,7 @@ const ALL_TABLE_NAMES: &'static [&'static str] = &[ "ai_text_chunk", "asset_entity_binding", "asset_object", + "auth_identity", "auth_store_snapshot", "battle_state", "big_fish_agent_message", @@ -2272,11 +2278,13 @@ const ALL_TABLE_NAMES: &'static [&'static str] = &[ "puzzle_work_profile", "quest_log", "quest_record", + "refresh_session", "runtime_setting", "runtime_snapshot", "story_event", "story_session", "treasure_record", + "user_account", "user_browse_history", ]; } diff --git a/server-rs/crates/spacetime-client/src/module_bindings/refresh_session_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/refresh_session_table.rs new file mode 100644 index 00000000..6c92ecfb --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/refresh_session_table.rs @@ -0,0 +1,163 @@ +// 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::refresh_session_type::RefreshSession; + +/// Table handle for the table `refresh_session`. +/// +/// Obtain a handle from the [`RefreshSessionTableAccess::refresh_session`] method on [`super::RemoteTables`], +/// like `ctx.db.refresh_session()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.refresh_session().on_insert(...)`. +pub struct RefreshSessionTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `refresh_session`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait RefreshSessionTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`RefreshSessionTableHandle`], which mediates access to the table `refresh_session`. + fn refresh_session(&self) -> RefreshSessionTableHandle<'_>; +} + +impl RefreshSessionTableAccess for super::RemoteTables { + fn refresh_session(&self) -> RefreshSessionTableHandle<'_> { + RefreshSessionTableHandle { + imp: self.imp.get_table::("refresh_session"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct RefreshSessionInsertCallbackId(__sdk::CallbackId); +pub struct RefreshSessionDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for RefreshSessionTableHandle<'ctx> { + type Row = RefreshSession; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { self.imp.count() } + fn iter(&self) -> impl Iterator + '_ { self.imp.iter() } + + type InsertCallbackId = RefreshSessionInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> RefreshSessionInsertCallbackId { + RefreshSessionInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: RefreshSessionInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = RefreshSessionDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> RefreshSessionDeleteCallbackId { + RefreshSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: RefreshSessionDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +pub struct RefreshSessionUpdateCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::TableWithPrimaryKey for RefreshSessionTableHandle<'ctx> { + type UpdateCallbackId = RefreshSessionUpdateCallbackId; + + fn on_update( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, + ) -> RefreshSessionUpdateCallbackId { + RefreshSessionUpdateCallbackId(self.imp.on_update(Box::new(callback))) + } + + fn remove_on_update(&self, callback: RefreshSessionUpdateCallbackId) { + self.imp.remove_on_update(callback.0) + } +} + + /// Access to the `session_id` unique index on the table `refresh_session`, + /// which allows point queries on the field of the same name + /// via the [`RefreshSessionSessionIdUnique::find`] method. + /// + /// Users are encouraged not to explicitly reference this type, + /// but to directly chain method calls, + /// like `ctx.db.refresh_session().session_id().find(...)`. + pub struct RefreshSessionSessionIdUnique<'ctx> { + imp: __sdk::UniqueConstraintHandle, + phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, + } + + impl<'ctx> RefreshSessionTableHandle<'ctx> { + /// Get a handle on the `session_id` unique index on the table `refresh_session`. + pub fn session_id(&self) -> RefreshSessionSessionIdUnique<'ctx> { + RefreshSessionSessionIdUnique { + imp: self.imp.get_unique_constraint::("session_id"), + phantom: std::marker::PhantomData, + } + } + } + + impl<'ctx> RefreshSessionSessionIdUnique<'ctx> { + /// Find the subscribed row whose `session_id` column value is equal to `col_val`, + /// if such a row is present in the client cache. + pub fn find(&self, col_val: &String) -> Option { + self.imp.find(col_val) + } + } + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + + let _table = client_cache.get_or_make_table::("refresh_session"); + _table.add_unique_constraint::("session_id", |row| &row.session_id); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::v2::TableUpdate, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse( + "TableUpdate", + "TableUpdate", + ).with_cause(e).into() + }) +} + + #[allow(non_camel_case_types)] + /// Extension trait for query builder access to the table `RefreshSession`. + /// + /// Implemented for [`__sdk::QueryTableAccessor`]. + pub trait refresh_sessionQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `RefreshSession`. + fn refresh_session(&self) -> __sdk::__query_builder::Table; + } + + impl refresh_sessionQueryTableAccess for __sdk::QueryTableAccessor { + fn refresh_session(&self) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("refresh_session") + } + } + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/refresh_session_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/refresh_session_type.rs new file mode 100644 index 00000000..5e7369e3 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/refresh_session_type.rs @@ -0,0 +1,91 @@ +// 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 RefreshSession { + 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::, + pub created_at: String, + pub updated_at: String, + pub last_seen_at: String, +} + + +impl __sdk::InModule for RefreshSession { + type Module = super::RemoteModule; +} + + +/// Column accessor struct for the table `RefreshSession`. +/// +/// Provides typed access to columns for query building. +pub struct RefreshSessionCols { + pub session_id: __sdk::__query_builder::Col, + pub user_id: __sdk::__query_builder::Col, + pub refresh_token_hash: __sdk::__query_builder::Col, + pub issued_by_provider: __sdk::__query_builder::Col, + pub client_info_json: __sdk::__query_builder::Col, + pub expires_at: __sdk::__query_builder::Col, + pub revoked_at: __sdk::__query_builder::Col>, + pub created_at: __sdk::__query_builder::Col, + pub updated_at: __sdk::__query_builder::Col, + pub last_seen_at: __sdk::__query_builder::Col, +} + +impl __sdk::__query_builder::HasCols for RefreshSession { + type Cols = RefreshSessionCols; + fn cols(table_name: &'static str) -> Self::Cols { + RefreshSessionCols { + session_id: __sdk::__query_builder::Col::new(table_name, "session_id"), + user_id: __sdk::__query_builder::Col::new(table_name, "user_id"), + refresh_token_hash: __sdk::__query_builder::Col::new(table_name, "refresh_token_hash"), + issued_by_provider: __sdk::__query_builder::Col::new(table_name, "issued_by_provider"), + client_info_json: __sdk::__query_builder::Col::new(table_name, "client_info_json"), + expires_at: __sdk::__query_builder::Col::new(table_name, "expires_at"), + revoked_at: __sdk::__query_builder::Col::new(table_name, "revoked_at"), + created_at: __sdk::__query_builder::Col::new(table_name, "created_at"), + updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"), + last_seen_at: __sdk::__query_builder::Col::new(table_name, "last_seen_at"), + + } + } +} + +/// Indexed column accessor struct for the table `RefreshSession`. +/// +/// Provides typed access to indexed columns for query building. +pub struct RefreshSessionIxCols { + pub refresh_token_hash: __sdk::__query_builder::IxCol, + pub session_id: __sdk::__query_builder::IxCol, + pub user_id: __sdk::__query_builder::IxCol, +} + +impl __sdk::__query_builder::HasIxCols for RefreshSession { + type IxCols = RefreshSessionIxCols; + fn ix_cols(table_name: &'static str) -> Self::IxCols { + RefreshSessionIxCols { + refresh_token_hash: __sdk::__query_builder::IxCol::new(table_name, "refresh_token_hash"), + session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), + user_id: __sdk::__query_builder::IxCol::new(table_name, "user_id"), + + } + } +} + +impl __sdk::__query_builder::CanBeLookupTable for RefreshSession {} + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_type_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_type_type.rs index 60ee2ecf..da820cbc 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_type_type.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/rpg_agent_operation_type_type.rs @@ -25,6 +25,10 @@ pub enum RpgAgentOperationType { GenerateLandmarks, + DeleteCharacters, + + DeleteLandmarks, + GenerateRoleAssets, SyncRoleAssets, diff --git a/server-rs/crates/spacetime-client/src/module_bindings/user_account_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/user_account_table.rs new file mode 100644 index 00000000..082d5303 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/user_account_table.rs @@ -0,0 +1,163 @@ +// 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::user_account_type::UserAccount; + +/// Table handle for the table `user_account`. +/// +/// Obtain a handle from the [`UserAccountTableAccess::user_account`] method on [`super::RemoteTables`], +/// like `ctx.db.user_account()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.user_account().on_insert(...)`. +pub struct UserAccountTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `user_account`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait UserAccountTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`UserAccountTableHandle`], which mediates access to the table `user_account`. + fn user_account(&self) -> UserAccountTableHandle<'_>; +} + +impl UserAccountTableAccess for super::RemoteTables { + fn user_account(&self) -> UserAccountTableHandle<'_> { + UserAccountTableHandle { + imp: self.imp.get_table::("user_account"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct UserAccountInsertCallbackId(__sdk::CallbackId); +pub struct UserAccountDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for UserAccountTableHandle<'ctx> { + type Row = UserAccount; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { self.imp.count() } + fn iter(&self) -> impl Iterator + '_ { self.imp.iter() } + + type InsertCallbackId = UserAccountInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> UserAccountInsertCallbackId { + UserAccountInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: UserAccountInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = UserAccountDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> UserAccountDeleteCallbackId { + UserAccountDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: UserAccountDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +pub struct UserAccountUpdateCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::TableWithPrimaryKey for UserAccountTableHandle<'ctx> { + type UpdateCallbackId = UserAccountUpdateCallbackId; + + fn on_update( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static, + ) -> UserAccountUpdateCallbackId { + UserAccountUpdateCallbackId(self.imp.on_update(Box::new(callback))) + } + + fn remove_on_update(&self, callback: UserAccountUpdateCallbackId) { + self.imp.remove_on_update(callback.0) + } +} + + /// Access to the `user_id` unique index on the table `user_account`, + /// which allows point queries on the field of the same name + /// via the [`UserAccountUserIdUnique::find`] method. + /// + /// Users are encouraged not to explicitly reference this type, + /// but to directly chain method calls, + /// like `ctx.db.user_account().user_id().find(...)`. + pub struct UserAccountUserIdUnique<'ctx> { + imp: __sdk::UniqueConstraintHandle, + phantom: std::marker::PhantomData<&'ctx super::RemoteTables>, + } + + impl<'ctx> UserAccountTableHandle<'ctx> { + /// Get a handle on the `user_id` unique index on the table `user_account`. + pub fn user_id(&self) -> UserAccountUserIdUnique<'ctx> { + UserAccountUserIdUnique { + imp: self.imp.get_unique_constraint::("user_id"), + phantom: std::marker::PhantomData, + } + } + } + + impl<'ctx> UserAccountUserIdUnique<'ctx> { + /// Find the subscribed row whose `user_id` column value is equal to `col_val`, + /// if such a row is present in the client cache. + pub fn find(&self, col_val: &String) -> Option { + self.imp.find(col_val) + } + } + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + + let _table = client_cache.get_or_make_table::("user_account"); + _table.add_unique_constraint::("user_id", |row| &row.user_id); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::v2::TableUpdate, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse( + "TableUpdate", + "TableUpdate", + ).with_cause(e).into() + }) +} + + #[allow(non_camel_case_types)] + /// Extension trait for query builder access to the table `UserAccount`. + /// + /// Implemented for [`__sdk::QueryTableAccessor`]. + pub trait user_accountQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `UserAccount`. + fn user_account(&self) -> __sdk::__query_builder::Table; + } + + impl user_accountQueryTableAccess for __sdk::QueryTableAccessor { + fn user_account(&self) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("user_account") + } + } + diff --git a/server-rs/crates/spacetime-client/src/module_bindings/user_account_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/user_account_type.rs new file mode 100644 index 00000000..49cf4cd1 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/user_account_type.rs @@ -0,0 +1,97 @@ +// 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 UserAccount { + pub user_id: String, + pub public_user_code: String, + pub username: String, + pub display_name: String, + pub phone_number_masked: Option::, + pub phone_number_e_164: Option::, + 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, +} + + +impl __sdk::InModule for UserAccount { + type Module = super::RemoteModule; +} + + +/// Column accessor struct for the table `UserAccount`. +/// +/// Provides typed access to columns for query building. +pub struct UserAccountCols { + pub user_id: __sdk::__query_builder::Col, + pub public_user_code: __sdk::__query_builder::Col, + pub username: __sdk::__query_builder::Col, + pub display_name: __sdk::__query_builder::Col, + pub phone_number_masked: __sdk::__query_builder::Col>, + pub phone_number_e_164: __sdk::__query_builder::Col>, + pub login_method: __sdk::__query_builder::Col, + pub binding_status: __sdk::__query_builder::Col, + pub wechat_bound: __sdk::__query_builder::Col, + pub password_hash: __sdk::__query_builder::Col, + pub password_login_enabled: __sdk::__query_builder::Col, + pub token_version: __sdk::__query_builder::Col, +} + +impl __sdk::__query_builder::HasCols for UserAccount { + type Cols = UserAccountCols; + fn cols(table_name: &'static str) -> Self::Cols { + UserAccountCols { + user_id: __sdk::__query_builder::Col::new(table_name, "user_id"), + public_user_code: __sdk::__query_builder::Col::new(table_name, "public_user_code"), + username: __sdk::__query_builder::Col::new(table_name, "username"), + display_name: __sdk::__query_builder::Col::new(table_name, "display_name"), + phone_number_masked: __sdk::__query_builder::Col::new(table_name, "phone_number_masked"), + phone_number_e_164: __sdk::__query_builder::Col::new(table_name, "phone_number_e_164"), + login_method: __sdk::__query_builder::Col::new(table_name, "login_method"), + binding_status: __sdk::__query_builder::Col::new(table_name, "binding_status"), + wechat_bound: __sdk::__query_builder::Col::new(table_name, "wechat_bound"), + password_hash: __sdk::__query_builder::Col::new(table_name, "password_hash"), + password_login_enabled: __sdk::__query_builder::Col::new(table_name, "password_login_enabled"), + token_version: __sdk::__query_builder::Col::new(table_name, "token_version"), + + } + } +} + +/// Indexed column accessor struct for the table `UserAccount`. +/// +/// Provides typed access to indexed columns for query building. +pub struct UserAccountIxCols { + pub public_user_code: __sdk::__query_builder::IxCol, + pub user_id: __sdk::__query_builder::IxCol, + pub username: __sdk::__query_builder::IxCol, +} + +impl __sdk::__query_builder::HasIxCols for UserAccount { + type IxCols = UserAccountIxCols; + fn ix_cols(table_name: &'static str) -> Self::IxCols { + UserAccountIxCols { + public_user_code: __sdk::__query_builder::IxCol::new(table_name, "public_user_code"), + user_id: __sdk::__query_builder::IxCol::new(table_name, "user_id"), + username: __sdk::__query_builder::IxCol::new(table_name, "username"), + + } + } +} + +impl __sdk::__query_builder::CanBeLookupTable for UserAccount {} + diff --git a/server-rs/crates/spacetime-client/src/npc.rs b/server-rs/crates/spacetime-client/src/npc.rs index 6d9a0367..8abaab4e 100644 --- a/server-rs/crates/spacetime-client/src/npc.rs +++ b/server-rs/crates/spacetime-client/src/npc.rs @@ -1,12 +1,13 @@ use super::*; +use crate::mapper::*; impl SpacetimeClient { pub async fn resolve_npc_battle_interaction( &self, - input: ResolveNpcBattleInteractionInput, + input: crate::mapper::ResolveNpcBattleInteractionInput, ) -> Result { validate_npc_battle_interaction_input(&input)?; - let procedure_input = map_resolve_npc_battle_interaction_input(input); + let procedure_input = input.into(); self.call_after_connect(move |connection, sender| { connection @@ -23,6 +24,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/puzzle.rs b/server-rs/crates/spacetime-client/src/puzzle.rs index 60e1f5b6..1b9c454e 100644 --- a/server-rs/crates/spacetime-client/src/puzzle.rs +++ b/server-rs/crates/spacetime-client/src/puzzle.rs @@ -1,4 +1,5 @@ use super::*; +use crate::mapper::*; impl SpacetimeClient { pub async fn create_puzzle_agent_session( @@ -28,7 +29,6 @@ impl SpacetimeClient { .await } - pub async fn get_puzzle_agent_session( &self, session_id: String, @@ -53,7 +53,6 @@ impl SpacetimeClient { .await } - pub async fn submit_puzzle_agent_message( &self, input: PuzzleAgentMessageSubmitRecordInput, @@ -80,7 +79,6 @@ impl SpacetimeClient { .await } - pub async fn finalize_puzzle_agent_message( &self, input: PuzzleAgentMessageFinalizeRecordInput, @@ -110,7 +108,6 @@ impl SpacetimeClient { .await } - pub async fn compile_puzzle_agent_draft( &self, session_id: String, @@ -137,7 +134,6 @@ impl SpacetimeClient { .await } - pub async fn save_puzzle_generated_images( &self, input: PuzzleGeneratedImagesSaveRecordInput, @@ -163,7 +159,6 @@ impl SpacetimeClient { .await } - pub async fn select_puzzle_cover_image( &self, input: PuzzleSelectCoverImageRecordInput, @@ -189,7 +184,6 @@ impl SpacetimeClient { .await } - pub async fn publish_puzzle_work( &self, input: PuzzlePublishRecordInput, @@ -219,7 +213,6 @@ impl SpacetimeClient { .await } - pub async fn list_puzzle_works( &self, owner_user_id: String, @@ -239,7 +232,6 @@ impl SpacetimeClient { .await } - pub async fn get_puzzle_work_detail( &self, profile_id: String, @@ -260,7 +252,6 @@ impl SpacetimeClient { .await } - pub async fn update_puzzle_work( &self, input: PuzzleWorkUpsertRecordInput, @@ -289,7 +280,6 @@ impl SpacetimeClient { .await } - pub async fn list_puzzle_gallery( &self, ) -> Result, SpacetimeClientError> { @@ -306,7 +296,6 @@ impl SpacetimeClient { .await } - pub async fn get_puzzle_gallery_detail( &self, profile_id: String, @@ -327,7 +316,6 @@ impl SpacetimeClient { .await } - pub async fn start_puzzle_run( &self, input: PuzzleRunStartRecordInput, @@ -352,7 +340,6 @@ impl SpacetimeClient { .await } - pub async fn get_puzzle_run( &self, run_id: String, @@ -376,7 +363,6 @@ impl SpacetimeClient { .await } - pub async fn swap_puzzle_pieces( &self, input: PuzzleRunSwapRecordInput, @@ -402,7 +388,6 @@ impl SpacetimeClient { .await } - pub async fn drag_puzzle_piece_or_group( &self, input: PuzzleRunDragRecordInput, @@ -430,7 +415,6 @@ impl SpacetimeClient { .await } - pub async fn advance_puzzle_next_level( &self, input: PuzzleRunNextLevelRecordInput, @@ -454,6 +438,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/runtime.rs b/server-rs/crates/spacetime-client/src/runtime.rs index 05435f6c..82d333e7 100644 --- a/server-rs/crates/spacetime-client/src/runtime.rs +++ b/server-rs/crates/spacetime-client/src/runtime.rs @@ -5,10 +5,9 @@ impl SpacetimeClient { &self, user_id: String, ) -> Result { - let procedure_input = map_runtime_setting_get_input( - build_runtime_setting_get_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_setting_get_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().get_runtime_setting_or_default_then( @@ -24,15 +23,13 @@ impl SpacetimeClient { .await } - pub async fn list_platform_browse_history( &self, user_id: String, ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_browse_history_list_input( - build_runtime_browse_history_list_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_browse_history_list_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().list_platform_browse_history_then( @@ -48,15 +45,13 @@ impl SpacetimeClient { .await } - pub async fn get_profile_dashboard( &self, user_id: String, ) -> Result { - let procedure_input = map_runtime_profile_dashboard_get_input( - build_runtime_profile_dashboard_get_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_profile_dashboard_get_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().get_profile_dashboard_then( @@ -72,15 +67,13 @@ impl SpacetimeClient { .await } - pub async fn list_profile_wallet_ledger( &self, user_id: String, ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_profile_wallet_ledger_list_input( - build_runtime_profile_wallet_ledger_list_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_profile_wallet_ledger_list_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().list_profile_wallet_ledger_then( @@ -96,15 +89,13 @@ impl SpacetimeClient { .await } - pub async fn get_profile_play_stats( &self, user_id: String, ) -> Result { - let procedure_input = map_runtime_profile_play_stats_get_input( - build_runtime_profile_play_stats_get_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_profile_play_stats_get_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().get_profile_play_stats_then( @@ -120,15 +111,13 @@ impl SpacetimeClient { .await } - pub async fn get_runtime_snapshot( &self, user_id: String, ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_snapshot_get_input( - build_runtime_snapshot_get_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_snapshot_get_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection @@ -143,7 +132,6 @@ impl SpacetimeClient { .await } - pub async fn put_runtime_snapshot( &self, user_id: String, @@ -153,17 +141,16 @@ impl SpacetimeClient { current_story: Option, updated_at_micros: i64, ) -> Result { - let procedure_input = map_runtime_snapshot_upsert_input( - build_runtime_snapshot_upsert_input( - user_id, - saved_at_micros, - bottom_tab, - game_state, - current_story, - updated_at_micros, - ) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_snapshot_upsert_input( + user_id, + saved_at_micros, + bottom_tab, + game_state, + current_story, + updated_at_micros, + ) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection @@ -178,15 +165,13 @@ impl SpacetimeClient { .await } - pub async fn delete_runtime_snapshot( &self, user_id: String, ) -> Result { - let procedure_input = map_runtime_snapshot_delete_input( - build_runtime_snapshot_delete_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_snapshot_delete_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection @@ -201,15 +186,13 @@ impl SpacetimeClient { .await } - pub async fn list_profile_save_archives( &self, user_id: String, ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_profile_save_archive_list_input( - build_runtime_profile_save_archive_list_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_profile_save_archive_list_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().list_profile_save_archives_then( @@ -225,17 +208,15 @@ impl SpacetimeClient { .await } - pub async fn resume_profile_save_archive( &self, user_id: String, world_key: String, ) -> Result<(RuntimeProfileSaveArchiveRecord, RuntimeSnapshotRecord), SpacetimeClientError> { - let procedure_input = map_runtime_profile_save_archive_resume_input( - build_runtime_profile_save_archive_resume_input(user_id, world_key) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_profile_save_archive_resume_input(user_id, world_key) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection @@ -250,23 +231,21 @@ impl SpacetimeClient { .await } - pub async fn put_runtime_settings( &self, user_id: String, music_volume: f32, - platform_theme: RuntimePlatformTheme, + platform_theme: DomainRuntimePlatformTheme, updated_at_micros: i64, ) -> Result { - let procedure_input = map_runtime_setting_upsert_input( - build_runtime_setting_upsert_input( - user_id, - music_volume, - platform_theme, - updated_at_micros, - ) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_setting_upsert_input( + user_id, + music_volume, + platform_theme, + updated_at_micros, + ) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection @@ -281,17 +260,16 @@ impl SpacetimeClient { .await } - pub async fn upsert_platform_browse_history_entries( &self, user_id: String, entries: Vec, updated_at_micros: i64, ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_browse_history_sync_input( + let procedure_input = build_runtime_browse_history_sync_input(user_id, entries, updated_at_micros) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection @@ -309,15 +287,13 @@ impl SpacetimeClient { .await } - pub async fn clear_platform_browse_history( &self, user_id: String, ) -> Result, SpacetimeClientError> { - let procedure_input = map_runtime_browse_history_clear_input( - build_runtime_browse_history_clear_input(user_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_runtime_browse_history_clear_input(user_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection @@ -334,6 +310,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-client/src/story.rs b/server-rs/crates/spacetime-client/src/story.rs index 57eee7a2..4633629d 100644 --- a/server-rs/crates/spacetime-client/src/story.rs +++ b/server-rs/crates/spacetime-client/src/story.rs @@ -11,18 +11,17 @@ impl SpacetimeClient { opening_summary: Option, created_at_micros: i64, ) -> Result { - let procedure_input = map_story_session_input( - build_story_session_input( - story_session_id, - runtime_session_id, - actor_user_id, - world_profile_id, - initial_prompt, - opening_summary, - created_at_micros, - ) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_story_session_input( + story_session_id, + runtime_session_id, + actor_user_id, + world_profile_id, + initial_prompt, + opening_summary, + created_at_micros, + ) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().begin_story_session_and_return_then( @@ -38,7 +37,6 @@ impl SpacetimeClient { .await } - pub async fn continue_story( &self, story_session_id: String, @@ -47,16 +45,15 @@ impl SpacetimeClient { choice_function_id: Option, updated_at_micros: i64, ) -> Result { - let procedure_input = map_story_continue_input( - build_story_continue_input( - story_session_id, - event_id, - narrative_text, - choice_function_id, - updated_at_micros, - ) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_story_continue_input( + story_session_id, + event_id, + narrative_text, + choice_function_id, + updated_at_micros, + ) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().continue_story_and_return_then( @@ -72,15 +69,13 @@ impl SpacetimeClient { .await } - pub async fn get_story_session_state( &self, story_session_id: String, ) -> Result { - let procedure_input = map_story_session_state_input( - build_story_session_state_input(story_session_id) - .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))?, - ); + let procedure_input = build_story_session_state_input(story_session_id) + .map_err(|error| SpacetimeClientError::Runtime(error.to_string()))? + .into(); self.call_after_connect(move |connection, sender| { connection.procedures().get_story_session_state_then( @@ -95,6 +90,4 @@ impl SpacetimeClient { }) .await } - - } diff --git a/server-rs/crates/spacetime-module/src/auth.rs b/server-rs/crates/spacetime-module/src/auth.rs index 13d7c171..cde789e7 100644 --- a/server-rs/crates/spacetime-module/src/auth.rs +++ b/server-rs/crates/spacetime-module/src/auth.rs @@ -1,4 +1,6 @@ use crate::*; +use serde::{Deserialize, Serialize}; +use serde_json::Value; const AUTH_STORE_SNAPSHOT_ID: &str = "default"; @@ -21,6 +23,20 @@ pub struct AuthStoreSnapshotProcedureResult { pub error_message: Option, } +#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] +pub struct AuthStoreSnapshotImportRecord { + pub imported_user_count: u32, + pub imported_identity_count: u32, + pub imported_refresh_session_count: u32, +} + +#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] +pub struct AuthStoreSnapshotImportProcedureResult { + pub ok: bool, + pub record: Option, + pub error_message: Option, +} + #[spacetimedb::table(accessor = auth_store_snapshot)] pub struct AuthStoreSnapshot { #[primary_key] @@ -29,6 +45,63 @@ pub struct AuthStoreSnapshot { pub(crate) updated_at: Timestamp, } +#[spacetimedb::table( + accessor = user_account, + index(accessor = by_user_account_username, btree(columns = [username])), + index(accessor = by_user_account_public_code, btree(columns = [public_user_code])) +)] +pub struct UserAccount { + #[primary_key] + pub(crate) user_id: String, + pub(crate) public_user_code: String, + pub(crate) username: String, + pub(crate) display_name: String, + pub(crate) phone_number_masked: Option, + pub(crate) phone_number_e164: Option, + pub(crate) login_method: String, + pub(crate) binding_status: String, + pub(crate) wechat_bound: bool, + pub(crate) password_hash: String, + pub(crate) password_login_enabled: bool, + pub(crate) token_version: u64, +} + +#[spacetimedb::table( + accessor = auth_identity, + index(accessor = by_auth_identity_user_id, btree(columns = [user_id])), + index(accessor = by_auth_identity_provider_uid, btree(columns = [provider, provider_uid])) +)] +pub struct AuthIdentity { + #[primary_key] + pub(crate) identity_id: String, + pub(crate) user_id: String, + pub(crate) provider: String, + pub(crate) provider_uid: String, + pub(crate) provider_union_id: Option, + pub(crate) phone_e164: Option, + pub(crate) display_name: Option, + pub(crate) avatar_url: Option, +} + +#[spacetimedb::table( + accessor = refresh_session, + index(accessor = by_refresh_session_user_id, btree(columns = [user_id])), + index(accessor = by_refresh_session_token_hash, btree(columns = [refresh_token_hash])) +)] +pub struct RefreshSession { + #[primary_key] + pub(crate) session_id: String, + pub(crate) user_id: String, + pub(crate) refresh_token_hash: String, + pub(crate) issued_by_provider: String, + pub(crate) client_info_json: String, + pub(crate) expires_at: String, + pub(crate) revoked_at: Option, + pub(crate) created_at: String, + pub(crate) updated_at: String, + pub(crate) last_seen_at: String, +} + // Axum 启动恢复认证状态时读取当前快照;记录不存在代表尚未产生登录态。 #[spacetimedb::procedure] pub fn get_auth_store_snapshot(ctx: &mut ProcedureContext) -> AuthStoreSnapshotProcedureResult { @@ -66,6 +139,43 @@ pub fn upsert_auth_store_snapshot( } } +#[spacetimedb::procedure] +pub fn import_auth_store_snapshot( + ctx: &mut ProcedureContext, +) -> AuthStoreSnapshotImportProcedureResult { + match ctx.try_with_tx(|tx| import_auth_store_snapshot_tx(tx)) { + Ok(record) => AuthStoreSnapshotImportProcedureResult { + ok: true, + record: Some(record), + error_message: None, + }, + Err(message) => AuthStoreSnapshotImportProcedureResult { + ok: false, + record: None, + error_message: Some(message), + }, + } +} + +// Axum ??????????????? module-auth ???????????????? +#[spacetimedb::procedure] +pub fn export_auth_store_snapshot_from_tables( + ctx: &mut ProcedureContext, +) -> AuthStoreSnapshotProcedureResult { + match ctx.try_with_tx(|tx| export_auth_store_snapshot_from_tables_tx(tx)) { + Ok(record) => AuthStoreSnapshotProcedureResult { + ok: true, + record: Some(record), + error_message: None, + }, + Err(message) => AuthStoreSnapshotProcedureResult { + ok: false, + record: None, + error_message: Some(message), + }, + } +} + fn get_auth_store_snapshot_tx(ctx: &ReducerContext) -> Result { Ok( match ctx @@ -120,3 +230,326 @@ fn upsert_auth_store_snapshot_tx( updated_at_micros: Some(input.updated_at_micros), }) } + +fn import_auth_store_snapshot_tx( + ctx: &ReducerContext, +) -> Result { + let snapshot = ctx + .db + .auth_store_snapshot() + .snapshot_id() + .find(&AUTH_STORE_SNAPSHOT_ID.to_string()) + .ok_or_else(|| "认证快照不存在,无法导入正式表".to_string())?; + let parsed = serde_json::from_str::(&snapshot.snapshot_json) + .map_err(|error| format!("认证快照 JSON 解析失败:{error}"))?; + + clear_auth_target_tables(ctx); + + let mut imported_user_count = 0_u32; + let mut imported_identity_count = 0_u32; + let mut imported_refresh_session_count = 0_u32; + + for stored_user in parsed.users_by_username.into_values() { + let user = stored_user.user; + ctx.db.user_account().insert(UserAccount { + user_id: user.id.clone(), + public_user_code: user.public_user_code, + username: user.username, + display_name: user.display_name, + phone_number_masked: user.phone_number_masked, + phone_number_e164: stored_user.phone_number.clone(), + login_method: user.login_method, + binding_status: user.binding_status, + wechat_bound: user.wechat_bound, + password_hash: stored_user.password_hash, + password_login_enabled: stored_user.password_login_enabled, + token_version: user.token_version, + }); + imported_user_count += 1; + + if let Some(phone_number) = stored_user.phone_number { + ctx.db.auth_identity().insert(AuthIdentity { + identity_id: format!("authi_phone_{}", sanitize_identity_component(&phone_number)), + user_id: user.id, + provider: "phone".to_string(), + provider_uid: phone_number.clone(), + provider_union_id: None, + phone_e164: Some(phone_number), + display_name: None, + avatar_url: None, + }); + imported_identity_count += 1; + } + } + + for identity in parsed.wechat_identity_by_provider_uid.into_values() { + ctx.db.auth_identity().insert(AuthIdentity { + identity_id: format!( + "authi_wechat_{}", + sanitize_identity_component(&identity.provider_uid) + ), + user_id: identity.user_id, + provider: "wechat".to_string(), + provider_uid: identity.provider_uid, + provider_union_id: identity.provider_union_id, + phone_e164: None, + display_name: identity.display_name, + avatar_url: identity.avatar_url, + }); + imported_identity_count += 1; + } + + for stored_session in parsed.sessions_by_id.into_values() { + let session = stored_session.session; + let client_info_json = serde_json::to_string(&session.client_info) + .map_err(|error| format!("客户端身份序列化失败:{error}"))?; + ctx.db.refresh_session().insert(RefreshSession { + 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, + 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, + }); + imported_refresh_session_count += 1; + } + + Ok(AuthStoreSnapshotImportRecord { + imported_user_count, + imported_identity_count, + imported_refresh_session_count, + }) +} + +fn export_auth_store_snapshot_from_tables_tx( + ctx: &ReducerContext, +) -> Result { + let users = ctx.db.user_account().iter().collect::>(); + let identities = ctx.db.auth_identity().iter().collect::>(); + let sessions = ctx.db.refresh_session().iter().collect::>(); + if users.is_empty() && identities.is_empty() && sessions.is_empty() { + return Ok(AuthStoreSnapshotRecord { + snapshot_json: None, + updated_at_micros: None, + }); + } + + let mut phone_identity_by_user_id = std::collections::HashMap::new(); + let mut phone_to_user_id = std::collections::HashMap::new(); + let mut wechat_identity_by_provider_uid = std::collections::HashMap::new(); + let mut user_id_by_provider_union_id = std::collections::HashMap::new(); + + for identity in identities { + match identity.provider.as_str() { + "phone" => { + let phone_number = identity + .phone_e164 + .clone() + .unwrap_or_else(|| identity.provider_uid.clone()); + phone_to_user_id.insert(phone_number.clone(), identity.user_id.clone()); + phone_identity_by_user_id.insert(identity.user_id, phone_number); + } + "wechat" => { + if let Some(union_id) = identity.provider_union_id.clone() { + user_id_by_provider_union_id.insert(union_id, identity.user_id.clone()); + } + wechat_identity_by_provider_uid.insert( + identity.provider_uid.clone(), + StoredWechatIdentitySnapshot { + user_id: identity.user_id, + provider_uid: identity.provider_uid, + provider_union_id: identity.provider_union_id, + display_name: identity.display_name, + avatar_url: identity.avatar_url, + }, + ); + } + _ => {} + } + } + + let mut next_user_id = 1_u64; + let mut users_by_username = std::collections::HashMap::new(); + for user in users { + if let Some(numeric_id) = user + .user_id + .strip_prefix("user_") + .and_then(|value| value.parse::().ok()) + { + next_user_id = next_user_id.max(numeric_id.saturating_add(1)); + } + let auth_user = AuthUserSnapshot { + id: user.user_id.clone(), + public_user_code: user.public_user_code, + username: user.username.clone(), + display_name: user.display_name, + phone_number_masked: user.phone_number_masked, + login_method: user.login_method, + binding_status: user.binding_status, + wechat_bound: user.wechat_bound, + token_version: user.token_version, + }; + users_by_username.insert( + user.username, + StoredPasswordUserSnapshot { + user: auth_user, + password_hash: user.password_hash, + password_login_enabled: user.password_login_enabled, + phone_number: user + .phone_number_e164 + .or_else(|| phone_identity_by_user_id.remove(&user.user_id)), + }, + ); + } + + let mut sessions_by_id = std::collections::HashMap::new(); + let mut session_id_by_refresh_token_hash = std::collections::HashMap::new(); + for session in sessions { + let client_info = serde_json::from_str::(&session.client_info_json) + .map_err(|error| format!("refresh session ????? JSON ?????{error}"))?; + session_id_by_refresh_token_hash.insert( + session.refresh_token_hash.clone(), + session.session_id.clone(), + ); + sessions_by_id.insert( + session.session_id.clone(), + StoredRefreshSessionSnapshot { + session: RefreshSessionSnapshot { + 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, + 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, + }, + }, + ); + } + + let snapshot = PersistentAuthStoreSnapshot { + next_user_id, + users_by_username, + phone_to_user_id, + sessions_by_id, + session_id_by_refresh_token_hash, + wechat_identity_by_provider_uid, + user_id_by_provider_union_id, + }; + let snapshot_json = + serde_json::to_string_pretty(&snapshot).map_err(|error| format!("?????????????{error}"))?; + + Ok(AuthStoreSnapshotRecord { + snapshot_json: Some(snapshot_json), + updated_at_micros: None, + }) +} + +fn clear_auth_target_tables(ctx: &ReducerContext) { + for row in ctx.db.refresh_session().iter().collect::>() { + ctx.db + .refresh_session() + .session_id() + .delete(&row.session_id); + } + for row in ctx.db.auth_identity().iter().collect::>() { + ctx.db + .auth_identity() + .identity_id() + .delete(&row.identity_id); + } + for row in ctx.db.user_account().iter().collect::>() { + ctx.db.user_account().user_id().delete(&row.user_id); + } +} + +fn sanitize_identity_component(value: &str) -> String { + let sanitized = value + .chars() + .map(|character| { + if character.is_ascii_alphanumeric() { + character + } else { + '_' + } + }) + .collect::(); + sanitized.trim_matches('_').to_string() +} + +#[derive(Deserialize, Serialize)] +struct PersistentAuthStoreSnapshot { + #[serde(default = "default_next_user_id")] + next_user_id: u64, + users_by_username: std::collections::HashMap, + #[serde(default)] + phone_to_user_id: std::collections::HashMap, + sessions_by_id: std::collections::HashMap, + #[serde(default)] + session_id_by_refresh_token_hash: std::collections::HashMap, + wechat_identity_by_provider_uid: + std::collections::HashMap, + #[serde(default)] + user_id_by_provider_union_id: std::collections::HashMap, +} + +fn default_next_user_id() -> u64 { + 1 +} + +#[derive(Deserialize, Serialize)] +struct StoredPasswordUserSnapshot { + user: AuthUserSnapshot, + password_hash: String, + #[serde(default)] + password_login_enabled: bool, + phone_number: Option, +} + +#[derive(Deserialize, Serialize)] +struct AuthUserSnapshot { + id: String, + public_user_code: String, + username: String, + display_name: String, + phone_number_masked: Option, + login_method: String, + binding_status: String, + wechat_bound: bool, + token_version: u64, +} + +#[derive(Deserialize, Serialize)] +struct StoredWechatIdentitySnapshot { + user_id: String, + provider_uid: String, + provider_union_id: Option, + display_name: Option, + avatar_url: Option, +} + +#[derive(Deserialize, Serialize)] +struct StoredRefreshSessionSnapshot { + session: RefreshSessionSnapshot, +} + +#[derive(Deserialize, Serialize)] +struct RefreshSessionSnapshot { + session_id: String, + user_id: String, + refresh_token_hash: String, + issued_by_provider: String, + client_info: Value, + expires_at: String, + revoked_at: Option, + created_at: String, + updated_at: String, + last_seen_at: String, +}