迁移后端认证与拆分 Spacetime 客户端

This commit is contained in:
2026-04-24 14:10:11 +08:00
parent ef53028be5
commit 4f369617c7
55 changed files with 9206 additions and 343 deletions

2
server-rs/Cargo.lock generated
View File

@@ -1518,6 +1518,8 @@ name = "module-auth"
version = "0.1.0"
dependencies = [
"platform-auth",
"serde",
"serde_json",
"shared-kernel",
"time",
"tokio",

View File

@@ -29,10 +29,12 @@
7. 基础 `TraceLayer` 挂载
8. 接入 `shared-logging` 完成 `tracing subscriber` 初始化
9. 接入 `POST /api/auth/entry` 首版密码登录链路
10. 接入 `POST /api/assets/direct-upload-tickets` 直传票据接口
11. 接入 `GET /api/auth/me` 当前用户查询链路
12. 接入 `POST /api/auth/refresh` refresh token 轮换链路
13. 接入 `POST /api/auth/logout` 当前设备退出链路
10. 接入 `POST /api/auth/password/change` 登录后修改密码链路
11. 接入 `POST /api/auth/password/reset` 手机验证码重置密码链路
12. 接入 `POST /api/assets/direct-upload-tickets` 直传票据接口
13. 接入 `GET /api/auth/me` 当前用户查询链路
14. 接入 `POST /api/auth/refresh` refresh token 轮换链路
15. 接入 `POST /api/auth/logout` 当前设备退出链路
14. 接入 `POST /api/assets/objects/confirm` 上传完成确认链路
15. 接入 `GET /api/auth/login-options` 登录方式探测链路
16. 接入 `POST /api/auth/phone/send-code` 手机验证码发送链路

View File

@@ -73,6 +73,7 @@ use crate::{
logout::logout,
logout_all::logout_all,
password_entry::password_entry,
password_management::{change_password, reset_password},
phone_auth::{phone_login, send_phone_code},
puzzle::{
advance_puzzle_next_level, create_puzzle_agent_session, drag_puzzle_piece_or_group,
@@ -887,6 +888,14 @@ pub fn build_router(state: AppState) -> Router {
)),
)
.route("/api/auth/entry", post(password_entry))
.route(
"/api/auth/password/change",
post(change_password).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route("/api/auth/password/reset", post(reset_password))
// 错误归一化层放在 tracing 里侧,让 tracing 记录到最终对外返回的状态与错误体形态。
.layer(middleware::from_fn(normalize_error_response))
// 响应头回写放在错误归一化外侧,确保最终写回的是归一化后的最终响应。

View File

@@ -66,7 +66,8 @@ fn map_public_user_search_error(error: module_auth::PasswordEntryError) -> AppEr
| module_auth::PasswordEntryError::PasswordHash(_)
| module_auth::PasswordEntryError::InvalidUsername
| module_auth::PasswordEntryError::InvalidPasswordLength
| module_auth::PasswordEntryError::InvalidCredentials => {
| module_auth::PasswordEntryError::InvalidCredentials
| module_auth::PasswordEntryError::UserNotFound => {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_message(error.to_string())
}
}

View File

@@ -7,6 +7,7 @@ use platform_llm::{
const DEFAULT_LLM_MODEL: &str = "doubao-1-5-pro-32k-character-250715";
const DEFAULT_INTERNAL_API_SECRET: &str = "genarrative-dev-internal-bridge";
const DEFAULT_AUTH_STORE_PATH: &str = "server-rs/.data/auth-store.json";
const SPACETIME_LOCAL_CONFIG_FILE: &str = "spacetime.local.json";
// 集中管理 api-server 的启动配置,避免入口层直接散落环境变量解析逻辑。
@@ -27,6 +28,7 @@ pub struct AppConfig {
pub refresh_cookie_secure: bool,
pub refresh_cookie_same_site: String,
pub refresh_session_ttl_days: u32,
pub auth_store_path: PathBuf,
pub sms_auth_enabled: bool,
pub sms_auth_provider: String,
pub sms_endpoint: String,
@@ -109,6 +111,7 @@ impl Default for AppConfig {
refresh_cookie_secure: false,
refresh_cookie_same_site: "Lax".to_string(),
refresh_session_ttl_days: 30,
auth_store_path: PathBuf::from(DEFAULT_AUTH_STORE_PATH),
sms_auth_enabled: false,
sms_auth_provider: "mock".to_string(),
sms_endpoint: "dypnsapi.aliyuncs.com".to_string(),
@@ -255,6 +258,10 @@ impl AppConfig {
config.refresh_session_ttl_days = refresh_session_ttl_days;
}
if let Some(auth_store_path) = read_first_non_empty_env(&["GENARRATIVE_AUTH_STORE_PATH"]) {
config.auth_store_path = PathBuf::from(auth_store_path);
}
if let Some(sms_auth_enabled) = read_first_bool_env(&["SMS_AUTH_ENABLED"]) {
config.sms_auth_enabled = sms_auth_enabled;
}

View File

@@ -988,10 +988,10 @@ pub async fn execute_custom_world_agent_action(
let result = state
.spacetime_client()
.execute_custom_world_agent_action(CustomWorldAgentActionExecuteRecordInput {
session_id,
owner_user_id,
session_id: session_id.clone(),
owner_user_id: owner_user_id.clone(),
operation_id: build_prefixed_uuid_id("operation-"),
action,
action: action.clone(),
payload_json: Some(payload_json),
submitted_at_micros,
})
@@ -1179,7 +1179,7 @@ fn log_custom_world_publish_gate_diagnostics(
blocker_codes = %blocker_codes,
has_draft_profile = session.draft_profile.as_object().map(|value| !value.is_empty()).unwrap_or(false),
has_result_preview = session.result_preview.is_some(),
preview_source = session.result_preview.as_ref().and_then(|value| value.get("source")).and_then(Value::as_str).unwrap_or(""),
preview_source = session.result_preview.as_ref().and_then(|value| value.get("source")).and_then(serde_json::Value::as_str).unwrap_or(""),
has_world_hook = has_custom_world_publish_text(profile, &["worldHook", "creatorIntent.worldHook", "anchorContent.worldPromise.hook", "settingText"]),
has_player_premise = has_custom_world_publish_text(profile, &["playerPremise", "creatorIntent.playerPremise", "anchorContent.playerEntryPoint.openingIdentity", "anchorContent.playerEntryPoint.openingProblem", "anchorContent.playerEntryPoint.entryMotivation"]),
has_core_conflicts = has_custom_world_non_empty_text_array(profile, "coreConflicts"),

View File

@@ -1,6 +1,6 @@
use axum::{
extract::{Extension, State},
http::HeaderMap,
http::{HeaderMap, StatusCode},
response::IntoResponse,
};
use module_auth::LogoutCurrentSessionInput;
@@ -44,6 +44,13 @@ pub async fn logout(
OffsetDateTime::now_utc(),
)
.map_err(map_logout_error)?;
state
.sync_auth_store_snapshot_to_spacetime()
.await
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR)
.with_message(format!("同步认证快照失败:{error}"))
})?;
let mut headers = HeaderMap::new();
attach_set_cookie_header(

View File

@@ -1,6 +1,6 @@
use axum::{
extract::{Extension, State},
http::HeaderMap,
http::{HeaderMap, StatusCode},
response::IntoResponse,
};
use module_auth::LogoutAllSessionsInput;
@@ -32,6 +32,13 @@ pub async fn logout_all(
OffsetDateTime::now_utc(),
)
.map_err(map_logout_error)?;
state
.sync_auth_store_snapshot_to_spacetime()
.await
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR)
.with_message(format!("同步认证快照失败:{error}"))
})?;
let mut headers = HeaderMap::new();
attach_set_cookie_header(

View File

@@ -29,6 +29,7 @@ mod login_options;
mod logout;
mod logout_all;
mod password_entry;
mod password_management;
mod phone_auth;
mod puzzle;
mod puzzle_agent_turn;
@@ -67,7 +68,8 @@ async fn main() -> Result<(), std::io::Error> {
let bind_address = config.bind_socket_addr();
let listener = TcpListener::bind(bind_address).await?;
let state = AppState::new(config)
let state = AppState::try_restore_auth_store_from_spacetime(config)
.await
.map_err(|error| std::io::Error::other(format!("初始化应用状态失败:{error}")))?;
let router = build_router(state);

View File

@@ -36,6 +36,13 @@ pub async fn password_entry(
.map_err(map_password_entry_error)?;
let session_client = resolve_session_client_context(&headers);
let signed_session = create_password_auth_session(&state, &result.user, &session_client)?;
state
.sync_auth_store_snapshot_to_spacetime()
.await
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR)
.with_message(format!("同步认证快照失败:{error}"))
})?;
let mut headers = HeaderMap::new();
attach_set_cookie_header(
@@ -75,6 +82,9 @@ fn map_password_entry_error(error: PasswordEntryError) -> AppError {
PasswordEntryError::InvalidCredentials => {
AppError::from_status(StatusCode::UNAUTHORIZED).with_message("用户名或密码错误")
}
PasswordEntryError::UserNotFound => {
AppError::from_status(StatusCode::UNAUTHORIZED).with_message("用户名或密码错误")
}
PasswordEntryError::Store(_) | PasswordEntryError::PasswordHash(_) => {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_message(error.to_string())
}

View File

@@ -0,0 +1,117 @@
use axum::{
Json,
extract::{Extension, State},
http::{HeaderMap, StatusCode},
response::IntoResponse,
};
use module_auth::{ChangePasswordInput, PasswordEntryError, ResetPasswordInput};
use shared_contracts::auth::{
PasswordChangeRequest, PasswordChangeResponse, PasswordResetRequest, PasswordResetResponse,
};
use time::OffsetDateTime;
use crate::{
api_response::json_success_body,
auth::AuthenticatedAccessToken,
auth_payload::map_auth_user_payload,
auth_session::{
attach_set_cookie_header, build_refresh_session_cookie_header, create_auth_session,
},
http_error::AppError,
phone_auth::map_phone_auth_error,
request_context::RequestContext,
session_client::resolve_session_client_context,
state::AppState,
};
pub async fn change_password(
State(state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
Json(payload): Json<PasswordChangeRequest>,
) -> Result<Json<serde_json::Value>, AppError> {
let result = state
.password_entry_service()
.change_password(ChangePasswordInput {
user_id: authenticated.claims().user_id().to_string(),
current_password: payload.current_password,
new_password: payload.new_password,
})
.await
.map_err(map_password_management_error)?;
Ok(json_success_body(
Some(&request_context),
PasswordChangeResponse {
user: map_auth_user_payload(result.user),
},
))
}
pub async fn reset_password(
State(state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
headers: HeaderMap,
Json(payload): Json<PasswordResetRequest>,
) -> Result<impl IntoResponse, AppError> {
if !state.config.sms_auth_enabled {
return Err(
AppError::from_status(StatusCode::BAD_REQUEST).with_message("手机号登录暂未启用")
);
}
let result = state
.phone_auth_service()
.reset_password(
ResetPasswordInput {
phone_number: payload.phone,
verify_code: payload.code,
new_password: payload.new_password,
},
OffsetDateTime::now_utc(),
)
.await
.map_err(map_phone_auth_error)?;
let session_client = resolve_session_client_context(&headers);
let signed_session = create_auth_session(
&state,
&result.user,
&session_client,
module_auth::AuthLoginMethod::Password,
)?;
let mut headers = HeaderMap::new();
attach_set_cookie_header(
&mut headers,
build_refresh_session_cookie_header(&state, &signed_session.refresh_token)?,
);
Ok((
headers,
json_success_body(
Some(&request_context),
PasswordResetResponse {
token: signed_session.access_token,
user: map_auth_user_payload(result.user),
},
),
))
}
fn map_password_management_error(error: PasswordEntryError) -> AppError {
match error {
PasswordEntryError::InvalidUsername | PasswordEntryError::InvalidPublicUserCode => {
AppError::from_status(StatusCode::BAD_REQUEST).with_message(error.to_string())
}
PasswordEntryError::InvalidPasswordLength => AppError::from_status(StatusCode::BAD_REQUEST)
.with_message("密码长度需要在 6 到 128 位之间"),
PasswordEntryError::InvalidCredentials => {
AppError::from_status(StatusCode::UNAUTHORIZED).with_message("当前密码错误")
}
PasswordEntryError::UserNotFound => AppError::from_status(StatusCode::UNAUTHORIZED)
.with_message("当前登录态已失效,请重新登录"),
PasswordEntryError::Store(_) | PasswordEntryError::PasswordHash(_) => {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_message(error.to_string())
}
}
}

View File

@@ -153,6 +153,13 @@ pub async fn phone_login(
&session_client,
AuthLoginMethod::Phone,
)?;
state
.sync_auth_store_snapshot_to_spacetime()
.await
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR)
.with_message(format!("同步认证快照失败:{error}"))
})?;
let mut headers = HeaderMap::new();
attach_set_cookie_header(
@@ -177,6 +184,7 @@ fn map_phone_auth_scene(raw_scene: Option<&str>) -> Result<PhoneAuthScene, AppEr
"login" => Ok(PhoneAuthScene::Login),
"bind_phone" => Ok(PhoneAuthScene::BindPhone),
"change_phone" => Ok(PhoneAuthScene::ChangePhone),
"reset_password" => Ok(PhoneAuthScene::ResetPassword),
_ => Err(AppError::from_status(StatusCode::BAD_REQUEST)
.with_message("短信验证码场景不合法")
.with_details(json!({ "field": "scene" }))),
@@ -214,7 +222,7 @@ fn mask_phone_digits(value: &str) -> String {
masked
}
fn map_phone_auth_error(error: PhoneAuthError) -> AppError {
pub fn map_phone_auth_error(error: PhoneAuthError) -> AppError {
match error {
PhoneAuthError::InvalidPhoneNumber
| PhoneAuthError::InvalidVerifyCode

View File

@@ -54,6 +54,13 @@ pub async fn refresh_session(
&rotated.session.session_id,
Some(&rotated.session.issued_by_provider),
)?;
state
.sync_auth_store_snapshot_to_spacetime()
.await
.map_err(|error| {
AppError::from_status(axum::http::StatusCode::INTERNAL_SERVER_ERROR)
.with_message(format!("同步认证快照失败:{error}"))
})?;
let mut headers = HeaderMap::new();
attach_set_cookie_header(

View File

@@ -21,6 +21,7 @@ use platform_oss::{OssClient, OssConfig, OssError};
use serde_json::Value;
use spacetime_client::{SpacetimeClient, SpacetimeClientConfig, SpacetimeClientError};
use time::OffsetDateTime;
use tracing::{info, warn};
use crate::config::AppConfig;
use crate::wechat_provider::{WechatProvider, build_wechat_provider};
@@ -37,6 +38,7 @@ pub struct AppState {
admin_runtime: Option<AdminRuntime>,
refresh_cookie_config: RefreshCookieConfig,
oss_client: Option<OssClient>,
auth_store: InMemoryAuthStore,
password_entry_service: PasswordEntryService,
refresh_session_service: RefreshSessionService,
auth_user_service: AuthUserService,
@@ -86,6 +88,7 @@ pub struct AdminSession {
pub enum AppStateInitError {
Jwt(JwtError),
RefreshCookie(RefreshCookieError),
AuthStore(String),
SmsProvider(SmsProviderError),
Oss(OssError),
Llm(LlmError),
@@ -93,6 +96,15 @@ pub enum AppStateInitError {
impl AppState {
pub fn new(config: AppConfig) -> Result<Self, AppStateInitError> {
let auth_store = InMemoryAuthStore::from_persistence_path(config.auth_store_path.clone())
.map_err(AppStateInitError::AuthStore)?;
Self::new_with_auth_store(config, auth_store)
}
fn new_with_auth_store(
config: AppConfig,
auth_store: InMemoryAuthStore,
) -> Result<Self, AppStateInitError> {
let auth_jwt_config = JwtConfig::new(
config.jwt_issuer.clone(),
config.jwt_secret.clone(),
@@ -111,7 +123,6 @@ impl AppState {
config.refresh_session_ttl_days,
)?;
let oss_client = build_oss_client(&config)?;
let auth_store = InMemoryAuthStore::default();
let sms_provider = SmsAuthProvider::new(SmsAuthConfig::new(
SmsAuthProviderKind::parse(&config.sms_auth_provider).ok_or_else(|| {
SmsProviderError::InvalidConfig("短信 provider 配置非法".to_string())
@@ -141,7 +152,7 @@ impl AppState {
let wechat_auth_service = WechatAuthService::new(auth_store.clone());
let wechat_provider = build_wechat_provider(&config);
let refresh_session_service =
RefreshSessionService::new(auth_store, config.refresh_session_ttl_days);
RefreshSessionService::new(auth_store.clone(), config.refresh_session_ttl_days);
// AI 编排服务当前先挂接内存态 store后续再按 task table / procedure 接到 SpacetimeDB 真相源。
let ai_task_service = AiTaskService::new(InMemoryAiTaskStore::default());
let spacetime_client = SpacetimeClient::new(SpacetimeClientConfig {
@@ -158,6 +169,7 @@ impl AppState {
admin_runtime,
refresh_cookie_config,
oss_client,
auth_store,
password_entry_service,
refresh_session_service,
auth_user_service,
@@ -193,6 +205,49 @@ impl AppState {
&self.password_entry_service
}
pub async fn sync_auth_store_snapshot_to_spacetime(&self) -> Result<(), SpacetimeClientError> {
let snapshot_json = self
.auth_store
.export_snapshot_json()
.map_err(SpacetimeClientError::Runtime)?;
let updated_at_micros = i64::try_from(
OffsetDateTime::now_utc().unix_timestamp_nanos() / 1_000,
)
.map_err(|_| SpacetimeClientError::Runtime("认证快照更新时间超出 i64 范围".to_string()))?;
self.spacetime_client
.upsert_auth_store_snapshot(snapshot_json, updated_at_micros)
.await?;
Ok(())
}
pub async fn try_restore_auth_store_from_spacetime(
config: AppConfig,
) -> Result<Self, AppStateInitError> {
let spacetime_client = SpacetimeClient::new(SpacetimeClientConfig {
server_url: config.spacetime_server_url.clone(),
database: config.spacetime_database.clone(),
token: config.spacetime_token.clone(),
pool_size: config.spacetime_pool_size,
});
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 恢复认证快照");
return Self::new_with_auth_store(config, auth_store);
}
}
}
Err(error) => {
warn!(error = %error, "从 SpacetimeDB 恢复认证快照失败,回退到本地快照");
}
}
Self::new(config)
}
pub fn refresh_session_service(&self) -> &RefreshSessionService {
&self.refresh_session_service
}
@@ -392,6 +447,7 @@ impl fmt::Display for AppStateInitError {
match self {
Self::Jwt(error) => write!(f, "{error}"),
Self::RefreshCookie(error) => write!(f, "{error}"),
Self::AuthStore(error) => write!(f, "{error}"),
Self::SmsProvider(error) => write!(f, "{error}"),
Self::Oss(error) => write!(f, "{error}"),
Self::Llm(error) => write!(f, "{error}"),

View File

@@ -135,6 +135,13 @@ pub async fn handle_wechat_callback(
&session_client,
AuthLoginMethod::Wechat,
)?;
state
.sync_auth_store_snapshot_to_spacetime()
.await
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR)
.with_message(format!("同步认证快照失败:{error}"))
})?;
let mut response = Redirect::to(&build_auth_result_redirect_url(
&redirect_path,
&[
@@ -187,6 +194,13 @@ pub async fn bind_wechat_phone(
&session_client,
AuthLoginMethod::Wechat,
)?;
state
.sync_auth_store_snapshot_to_spacetime()
.await
.map_err(|error| {
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR)
.with_message(format!("同步认证快照失败:{error}"))
})?;
let mut response_headers = HeaderMap::new();
attach_set_cookie_header(

View File

@@ -7,6 +7,8 @@ license.workspace = true
[dependencies]
platform-auth = { path = "../platform-auth" }
shared-kernel = { path = "../shared-kernel" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
time = { version = "0.3", features = ["formatting", "parsing"] }
tracing = "0.1"
uuid = { version = "1", features = ["v4"] }

File diff suppressed because it is too large Load Diff

View File

@@ -53,6 +53,34 @@ pub struct PasswordEntryResponse {
pub user: AuthUserPayload,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PasswordChangeRequest {
pub current_password: Option<String>,
pub new_password: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PasswordChangeResponse {
pub user: AuthUserPayload,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PasswordResetRequest {
pub phone: String,
pub code: String,
pub new_password: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PasswordResetResponse {
pub token: String,
pub user: AuthUserPayload,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct AuthMeResponse {
@@ -167,7 +195,7 @@ pub fn build_available_login_methods(
sms_auth_enabled: bool,
wechat_auth_enabled: bool,
) -> Vec<String> {
let mut methods = Vec::new();
let mut methods = vec![AUTH_LOGIN_METHOD_PASSWORD.to_string()];
if sms_auth_enabled {
methods.push(AUTH_LOGIN_METHOD_PHONE.to_string());
}
@@ -189,6 +217,7 @@ mod tests {
assert_eq!(
methods,
vec![
AUTH_LOGIN_METHOD_PASSWORD.to_string(),
AUTH_LOGIN_METHOD_PHONE.to_string(),
AUTH_LOGIN_METHOD_WECHAT.to_string()
]

View File

@@ -0,0 +1,205 @@
use super::*;
impl SpacetimeClient {
pub async fn create_ai_task(
&self,
input: DomainAiTaskCreateInput,
) -> Result<AiTaskMutationRecord, SpacetimeClientError> {
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<AiTaskMutationRecord, SpacetimeClientError> {
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<AiTaskMutationRecord, SpacetimeClientError> {
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<AiTaskMutationRecord, SpacetimeClientError> {
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<AiTaskMutationRecord, SpacetimeClientError> {
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<AiTaskMutationRecord, SpacetimeClientError> {
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<AiTaskMutationRecord, SpacetimeClientError> {
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
}
}

View File

@@ -0,0 +1,44 @@
use super::*;
impl SpacetimeClient {
pub async fn confirm_asset_object(
&self,
input: module_assets::AssetObjectUpsertInput,
) -> Result<AssetObjectRecord, SpacetimeClientError> {
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<AssetEntityBindingRecord, SpacetimeClientError> {
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
}
}

View File

@@ -0,0 +1,46 @@
use super::*;
impl SpacetimeClient {
pub async fn get_auth_store_snapshot(
&self,
) -> Result<AuthStoreSnapshotRecord, SpacetimeClientError> {
self.call_after_connect(move |connection, sender| {
connection
.procedures()
.get_auth_store_snapshot_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 upsert_auth_store_snapshot(
&self,
snapshot_json: String,
updated_at_micros: i64,
) -> Result<AuthStoreSnapshotRecord, SpacetimeClientError> {
let procedure_input = AuthStoreSnapshotUpsertInput {
snapshot_json,
updated_at_micros,
};
self.call_after_connect(move |connection, sender| {
connection.procedures().upsert_auth_store_snapshot_then(
procedure_input,
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
}
}

View File

@@ -0,0 +1,263 @@
use super::*;
impl SpacetimeClient {
pub async fn create_big_fish_session(
&self,
input: BigFishSessionCreateRecordInput,
) -> Result<BigFishSessionRecord, SpacetimeClientError> {
let procedure_input = BigFishSessionCreateInput {
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<BigFishSessionRecord, SpacetimeClientError> {
let procedure_input = BigFishSessionGetInput {
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<Vec<BigFishWorkSummaryRecord>, SpacetimeClientError> {
let procedure_input = BigFishWorksListInput { 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<BigFishSessionRecord, SpacetimeClientError> {
let procedure_input = BigFishMessageSubmitInput {
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 compile_big_fish_draft(
&self,
session_id: String,
owner_user_id: String,
compiled_at_micros: i64,
) -> Result<BigFishSessionRecord, SpacetimeClientError> {
let procedure_input = BigFishDraftCompileInput {
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<BigFishSessionRecord, SpacetimeClientError> {
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())?,
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<BigFishSessionRecord, SpacetimeClientError> {
let procedure_input = BigFishPublishInput {
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<BigFishRuntimeRecord, SpacetimeClientError> {
let procedure_input = BigFishRunStartInput {
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<BigFishRuntimeRecord, SpacetimeClientError> {
let procedure_input = BigFishRunInputSubmitInput {
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<BigFishRuntimeRecord, SpacetimeClientError> {
let procedure_input = BigFishRunGetInput {
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
}
}

View File

@@ -0,0 +1,72 @@
use super::*;
impl SpacetimeClient {
pub async fn create_battle_state(
&self,
input: DomainBattleStateInput,
) -> Result<BattleStateRecord, SpacetimeClientError> {
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<BattleStateRecord, SpacetimeClientError> {
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 resolve_combat_action(
&self,
input: DomainResolveCombatActionInput,
) -> Result<ResolveCombatActionRecord, SpacetimeClientError> {
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
}
}

View File

@@ -0,0 +1,481 @@
use super::*;
impl SpacetimeClient {
pub async fn list_custom_world_profiles(
&self,
owner_user_id: String,
) -> Result<Vec<CustomWorldLibraryEntryRecord>, SpacetimeClientError> {
let procedure_input = CustomWorldProfileListInput { 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<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
let procedure_input = CustomWorldLibraryDetailInput {
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<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
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<String>,
author_public_user_code: String,
author_display_name: String,
published_at_micros: i64,
) -> Result<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
let procedure_input = CustomWorldProfilePublishInput {
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<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
let procedure_input = CustomWorldProfileUnpublishInput {
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<Vec<CustomWorldLibraryEntryRecord>, SpacetimeClientError> {
let procedure_input = CustomWorldProfileDeleteInput {
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<Vec<CustomWorldGalleryEntryRecord>, 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<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
let procedure_input = CustomWorldGalleryDetailInput {
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<CustomWorldLibraryMutationRecord, SpacetimeClientError> {
let procedure_input = CustomWorldGalleryDetailByCodeInput { 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<CustomWorldPublishWorldRecord, SpacetimeClientError> {
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<CustomWorldAgentSessionRecord, SpacetimeClientError> {
let procedure_input = CustomWorldAgentSessionCreateInput {
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<CustomWorldAgentSessionRecord, SpacetimeClientError> {
let procedure_input = CustomWorldAgentSessionGetInput {
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<Vec<CustomWorldWorkSummaryRecord>, SpacetimeClientError> {
let procedure_input = CustomWorldWorksListInput { 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<CustomWorldDraftCardDetailRecord, SpacetimeClientError> {
let procedure_input = CustomWorldAgentCardDetailGetInput {
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<CustomWorldAgentActionExecuteRecord, SpacetimeClientError> {
let procedure_input = CustomWorldAgentActionExecuteInput {
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 submit_custom_world_agent_message(
&self,
input: CustomWorldAgentMessageSubmitRecordInput,
) -> Result<CustomWorldAgentOperationRecord, SpacetimeClientError> {
let procedure_input = CustomWorldAgentMessageSubmitInput {
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<CustomWorldAgentOperationRecord, SpacetimeClientError> {
let procedure_input = CustomWorldAgentMessageFinalizeInput {
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<CustomWorldAgentOperationRecord, SpacetimeClientError> {
let procedure_input = CustomWorldAgentOperationGetInput {
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
}
}

View File

@@ -0,0 +1,29 @@
use super::*;
impl SpacetimeClient {
pub async fn get_runtime_inventory_state(
&self,
runtime_session_id: String,
actor_user_id: String,
) -> Result<RuntimeInventoryStateRecord, SpacetimeClientError> {
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
}
}

View File

@@ -2,6 +2,21 @@
#[rustfmt::skip]
pub mod module_bindings;
mod mapper;
pub use mapper::*;
pub mod ai;
pub mod assets;
pub mod auth;
pub mod big_fish;
pub mod combat;
pub mod custom_world;
pub mod inventory;
pub mod npc;
pub mod puzzle;
pub mod runtime;
pub mod story;
use std::{
error::Error,
fmt,
@@ -69,9 +84,11 @@ use module_puzzle::{
PuzzleWorkProfile as DomainPuzzleWorkProfile,
};
use module_runtime::{
RuntimeBrowseHistoryRecord, RuntimeBrowseHistoryThemeMode, RuntimePlatformTheme,
RuntimeBrowseHistoryRecord, RuntimeBrowseHistoryThemeMode as DomainRuntimeBrowseHistoryThemeMode,
RuntimePlatformTheme as DomainRuntimePlatformTheme,
RuntimeProfileDashboardRecord, RuntimeProfilePlayStatsRecord, RuntimeProfileSaveArchiveRecord,
RuntimeProfileWalletLedgerEntryRecord, RuntimeProfileWalletLedgerSourceType,
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,
@@ -104,6 +121,7 @@ use tokio::{
time::timeout,
};
<<<<<<< HEAD
use crate::module_bindings::{
AiResultReferenceInput as BindingAiResultReferenceInput,
AiResultReferenceKind as BindingAiResultReferenceKind,
@@ -360,6 +378,9 @@ use crate::module_bindings::{
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 {
@@ -369,6 +390,12 @@ pub struct SpacetimeClientConfig {
pub pool_size: u32,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AuthStoreSnapshotRecord {
pub snapshot_json: Option<String>,
pub updated_at_micros: Option<i64>,
}
#[derive(Clone)]
pub struct SpacetimeClient {
config: SpacetimeClientConfig,
@@ -431,6 +458,7 @@ impl SpacetimeClient {
Self { config, pool }
}
<<<<<<< HEAD
pub async fn create_ai_task(
&self,
input: DomainAiTaskCreateInput,
@@ -2362,6 +2390,8 @@ impl SpacetimeClient {
.await
}
=======
>>>>>>> 4f272a50 ( Spacetime )
async fn call_after_connect<T>(
&self,
call: impl FnOnce(&DbConnection, ProcedureResultSender<T>) + Send + 'static,
@@ -2596,6 +2626,7 @@ fn send_connect_once(
}
}
<<<<<<< HEAD
fn map_entity_binding_input(
input: module_assets::AssetEntityBindingInput,
) -> BindingAssetEntityBindingInput {
@@ -7089,6 +7120,8 @@ fn map_inventory_item_source_kind(
}
}
=======
>>>>>>> 4f272a50 ( Spacetime )
impl fmt::Display for SpacetimeClientError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {

File diff suppressed because it is too large Load Diff

View File

@@ -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_record_type::AuthStoreSnapshotRecord;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreSnapshotProcedureResult {
pub ok: bool,
pub record: Option::<AuthStoreSnapshotRecord>,
pub error_message: Option::<String>,
}
impl __sdk::InModule for AuthStoreSnapshotProcedureResult {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,24 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{
self as __sdk,
__lib,
__sats,
__ws,
};
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreSnapshotRecord {
pub snapshot_json: Option::<String>,
pub updated_at_micros: Option::<i64>,
}
impl __sdk::InModule for AuthStoreSnapshotRecord {
type Module = super::RemoteModule;
}

View File

@@ -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_store_snapshot_type::AuthStoreSnapshot;
/// Table handle for the table `auth_store_snapshot`.
///
/// Obtain a handle from the [`AuthStoreSnapshotTableAccess::auth_store_snapshot`] method on [`super::RemoteTables`],
/// like `ctx.db.auth_store_snapshot()`.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.auth_store_snapshot().on_insert(...)`.
pub struct AuthStoreSnapshotTableHandle<'ctx> {
imp: __sdk::TableHandle<AuthStoreSnapshot>,
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `auth_store_snapshot`.
///
/// Implemented for [`super::RemoteTables`].
pub trait AuthStoreSnapshotTableAccess {
#[allow(non_snake_case)]
/// Obtain a [`AuthStoreSnapshotTableHandle`], which mediates access to the table `auth_store_snapshot`.
fn auth_store_snapshot(&self) -> AuthStoreSnapshotTableHandle<'_>;
}
impl AuthStoreSnapshotTableAccess for super::RemoteTables {
fn auth_store_snapshot(&self) -> AuthStoreSnapshotTableHandle<'_> {
AuthStoreSnapshotTableHandle {
imp: self.imp.get_table::<AuthStoreSnapshot>("auth_store_snapshot"),
ctx: std::marker::PhantomData,
}
}
}
pub struct AuthStoreSnapshotInsertCallbackId(__sdk::CallbackId);
pub struct AuthStoreSnapshotDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::Table for AuthStoreSnapshotTableHandle<'ctx> {
type Row = AuthStoreSnapshot;
type EventContext = super::EventContext;
fn count(&self) -> u64 { self.imp.count() }
fn iter(&self) -> impl Iterator<Item = AuthStoreSnapshot> + '_ { self.imp.iter() }
type InsertCallbackId = AuthStoreSnapshotInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AuthStoreSnapshotInsertCallbackId {
AuthStoreSnapshotInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: AuthStoreSnapshotInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
type DeleteCallbackId = AuthStoreSnapshotDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> AuthStoreSnapshotDeleteCallbackId {
AuthStoreSnapshotDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: AuthStoreSnapshotDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct AuthStoreSnapshotUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for AuthStoreSnapshotTableHandle<'ctx> {
type UpdateCallbackId = AuthStoreSnapshotUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> AuthStoreSnapshotUpdateCallbackId {
AuthStoreSnapshotUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: AuthStoreSnapshotUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `snapshot_id` unique index on the table `auth_store_snapshot`,
/// which allows point queries on the field of the same name
/// via the [`AuthStoreSnapshotSnapshotIdUnique::find`] method.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.auth_store_snapshot().snapshot_id().find(...)`.
pub struct AuthStoreSnapshotSnapshotIdUnique<'ctx> {
imp: __sdk::UniqueConstraintHandle<AuthStoreSnapshot, String>,
phantom: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
impl<'ctx> AuthStoreSnapshotTableHandle<'ctx> {
/// Get a handle on the `snapshot_id` unique index on the table `auth_store_snapshot`.
pub fn snapshot_id(&self) -> AuthStoreSnapshotSnapshotIdUnique<'ctx> {
AuthStoreSnapshotSnapshotIdUnique {
imp: self.imp.get_unique_constraint::<String>("snapshot_id"),
phantom: std::marker::PhantomData,
}
}
}
impl<'ctx> AuthStoreSnapshotSnapshotIdUnique<'ctx> {
/// Find the subscribed row whose `snapshot_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<AuthStoreSnapshot> {
self.imp.find(col_val)
}
}
#[doc(hidden)]
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
let _table = client_cache.get_or_make_table::<AuthStoreSnapshot>("auth_store_snapshot");
_table.add_unique_constraint::<String>("snapshot_id", |row| &row.snapshot_id);
}
#[doc(hidden)]
pub(super) fn parse_table_update(
raw_updates: __ws::v2::TableUpdate,
) -> __sdk::Result<__sdk::TableUpdate<AuthStoreSnapshot>> {
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
__sdk::InternalError::failed_parse(
"TableUpdate<AuthStoreSnapshot>",
"TableUpdate",
).with_cause(e).into()
})
}
#[allow(non_camel_case_types)]
/// Extension trait for query builder access to the table `AuthStoreSnapshot`.
///
/// Implemented for [`__sdk::QueryTableAccessor`].
pub trait auth_store_snapshotQueryTableAccess {
#[allow(non_snake_case)]
/// Get a query builder for the table `AuthStoreSnapshot`.
fn auth_store_snapshot(&self) -> __sdk::__query_builder::Table<AuthStoreSnapshot>;
}
impl auth_store_snapshotQueryTableAccess for __sdk::QueryTableAccessor {
fn auth_store_snapshot(&self) -> __sdk::__query_builder::Table<AuthStoreSnapshot> {
__sdk::__query_builder::Table::new("auth_store_snapshot")
}
}

View File

@@ -0,0 +1,66 @@
// 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 AuthStoreSnapshot {
pub snapshot_id: String,
pub snapshot_json: String,
pub updated_at: __sdk::Timestamp,
}
impl __sdk::InModule for AuthStoreSnapshot {
type Module = super::RemoteModule;
}
/// Column accessor struct for the table `AuthStoreSnapshot`.
///
/// Provides typed access to columns for query building.
pub struct AuthStoreSnapshotCols {
pub snapshot_id: __sdk::__query_builder::Col<AuthStoreSnapshot, String>,
pub snapshot_json: __sdk::__query_builder::Col<AuthStoreSnapshot, String>,
pub updated_at: __sdk::__query_builder::Col<AuthStoreSnapshot, __sdk::Timestamp>,
}
impl __sdk::__query_builder::HasCols for AuthStoreSnapshot {
type Cols = AuthStoreSnapshotCols;
fn cols(table_name: &'static str) -> Self::Cols {
AuthStoreSnapshotCols {
snapshot_id: __sdk::__query_builder::Col::new(table_name, "snapshot_id"),
snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"),
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
}
}
}
/// Indexed column accessor struct for the table `AuthStoreSnapshot`.
///
/// Provides typed access to indexed columns for query building.
pub struct AuthStoreSnapshotIxCols {
pub snapshot_id: __sdk::__query_builder::IxCol<AuthStoreSnapshot, String>,
}
impl __sdk::__query_builder::HasIxCols for AuthStoreSnapshot {
type IxCols = AuthStoreSnapshotIxCols;
fn ix_cols(table_name: &'static str) -> Self::IxCols {
AuthStoreSnapshotIxCols {
snapshot_id: __sdk::__query_builder::IxCol::new(table_name, "snapshot_id"),
}
}
}
impl __sdk::__query_builder::CanBeLookupTable for AuthStoreSnapshot {}

View File

@@ -0,0 +1,24 @@
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
#![allow(unused, clippy::all)]
use spacetimedb_sdk::__codegen::{
self as __sdk,
__lib,
__sats,
__ws,
};
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct AuthStoreSnapshotUpsertInput {
pub snapshot_json: String,
pub updated_at_micros: i64,
}
impl __sdk::InModule for AuthStoreSnapshotUpsertInput {
type Module = super::RemoteModule;
}

View File

@@ -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 GetAuthStoreSnapshotArgs {
}
impl __sdk::InModule for GetAuthStoreSnapshotArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `get_auth_store_snapshot`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait get_auth_store_snapshot {
fn get_auth_store_snapshot(&self, ) {
self.get_auth_store_snapshot_then( |_, _| {});
}
fn get_auth_store_snapshot_then(
&self,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<AuthStoreSnapshotProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl get_auth_store_snapshot for super::RemoteProcedures {
fn get_auth_store_snapshot_then(
&self,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<AuthStoreSnapshotProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, AuthStoreSnapshotProcedureResult>(
"get_auth_store_snapshot",
GetAuthStoreSnapshotArgs { },
__callback,
);
}
}

View File

@@ -44,6 +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_store_snapshot_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;
@@ -339,6 +346,10 @@ 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_store_snapshot_table;
>>>>>>> 4f272a50 ( Spacetime )
pub mod battle_state_table;
pub mod big_fish_agent_message_table;
pub mod big_fish_asset_slot_table;
@@ -396,10 +407,17 @@ 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 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;
@@ -452,6 +470,7 @@ pub mod submit_puzzle_agent_message_procedure;
pub mod swap_puzzle_pieces_procedure;
pub mod unpublish_custom_world_profile_and_return_procedure;
pub mod update_puzzle_work_procedure;
pub mod upsert_auth_store_snapshot_procedure;
pub mod upsert_chapter_progression_and_return_procedure;
pub mod upsert_custom_world_profile_and_return_procedure;
pub mod upsert_npc_state_and_return_procedure;
@@ -492,6 +511,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_store_snapshot_type::AuthStoreSnapshot;
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;
@@ -763,6 +789,10 @@ 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_store_snapshot_table::*;
>>>>>>> 4f272a50 ( Spacetime )
pub use battle_state_table::*;
pub use big_fish_agent_message_table::*;
pub use big_fish_asset_slot_table::*;
@@ -844,10 +874,17 @@ pub use delete_runtime_snapshot_and_return_procedure::delete_runtime_snapshot_an
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 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;
@@ -900,6 +937,7 @@ pub use submit_puzzle_agent_message_procedure::submit_puzzle_agent_message;
pub use swap_puzzle_pieces_procedure::swap_puzzle_pieces;
pub use unpublish_custom_world_profile_and_return_procedure::unpublish_custom_world_profile_and_return;
pub use update_puzzle_work_procedure::update_puzzle_work;
pub use upsert_auth_store_snapshot_procedure::upsert_auth_store_snapshot;
pub use upsert_chapter_progression_and_return_procedure::upsert_chapter_progression_and_return;
pub use upsert_custom_world_profile_and_return_procedure::upsert_custom_world_profile_and_return;
pub use upsert_npc_state_and_return_procedure::upsert_npc_state_and_return;
@@ -1162,6 +1200,7 @@ pub struct DbUpdate {
ai_text_chunk: __sdk::TableUpdate<AiTextChunk>,
asset_entity_binding: __sdk::TableUpdate<AssetEntityBinding>,
asset_object: __sdk::TableUpdate<AssetObject>,
auth_store_snapshot: __sdk::TableUpdate<AuthStoreSnapshot>,
battle_state: __sdk::TableUpdate<BattleState>,
big_fish_agent_message: __sdk::TableUpdate<BigFishAgentMessage>,
big_fish_asset_slot: __sdk::TableUpdate<BigFishAssetSlot>,
@@ -1210,6 +1249,10 @@ 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_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)?),
@@ -1270,6 +1313,10 @@ impl __sdk::DbUpdate for DbUpdate {
diff.ai_text_chunk = cache.apply_diff_to_table::<AiTextChunk>("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::<AssetEntityBinding>("asset_entity_binding", &self.asset_entity_binding).with_updates_by_pk(|row| &row.binding_id);
diff.asset_object = cache.apply_diff_to_table::<AssetObject>("asset_object", &self.asset_object).with_updates_by_pk(|row| &row.asset_object_id);
<<<<<<< HEAD
=======
diff.auth_store_snapshot = cache.apply_diff_to_table::<AuthStoreSnapshot>("auth_store_snapshot", &self.auth_store_snapshot).with_updates_by_pk(|row| &row.snapshot_id);
>>>>>>> 4f272a50 ( Spacetime )
diff.battle_state = cache.apply_diff_to_table::<BattleState>("battle_state", &self.battle_state).with_updates_by_pk(|row| &row.battle_state_id);
diff.big_fish_agent_message = cache.apply_diff_to_table::<BigFishAgentMessage>("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::<BigFishAssetSlot>("big_fish_asset_slot", &self.big_fish_asset_slot).with_updates_by_pk(|row| &row.slot_id);
@@ -1315,6 +1362,10 @@ 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_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)?),
@@ -1360,6 +1411,10 @@ 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_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)?),
@@ -1407,6 +1462,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_store_snapshot: __sdk::TableAppliedDiff<'r, AuthStoreSnapshot>,
battle_state: __sdk::TableAppliedDiff<'r, BattleState>,
big_fish_agent_message: __sdk::TableAppliedDiff<'r, BigFishAgentMessage>,
big_fish_asset_slot: __sdk::TableAppliedDiff<'r, BigFishAssetSlot>,
@@ -1455,6 +1511,10 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> {
callbacks.invoke_table_row_callbacks::<AiTextChunk>("ai_text_chunk", &self.ai_text_chunk, event);
callbacks.invoke_table_row_callbacks::<AssetEntityBinding>("asset_entity_binding", &self.asset_entity_binding, event);
callbacks.invoke_table_row_callbacks::<AssetObject>("asset_object", &self.asset_object, event);
<<<<<<< HEAD
=======
callbacks.invoke_table_row_callbacks::<AuthStoreSnapshot>("auth_store_snapshot", &self.auth_store_snapshot, event);
>>>>>>> 4f272a50 ( Spacetime )
callbacks.invoke_table_row_callbacks::<BattleState>("battle_state", &self.battle_state, event);
callbacks.invoke_table_row_callbacks::<BigFishAgentMessage>("big_fish_agent_message", &self.big_fish_agent_message, event);
callbacks.invoke_table_row_callbacks::<BigFishAssetSlot>("big_fish_asset_slot", &self.big_fish_asset_slot, event);
@@ -2144,6 +2204,7 @@ fn register_tables(client_cache: &mut __sdk::ClientCache<Self>) {
ai_text_chunk_table::register_table(client_cache);
asset_entity_binding_table::register_table(client_cache);
asset_object_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);
big_fish_asset_slot_table::register_table(client_cache);
@@ -2184,6 +2245,7 @@ const ALL_TABLE_NAMES: &'static [&'static str] = &[
"ai_text_chunk",
"asset_entity_binding",
"asset_object",
"auth_store_snapshot",
"battle_state",
"big_fish_agent_message",
"big_fish_asset_slot",

View File

@@ -0,0 +1,58 @@
// 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;
use super::auth_store_snapshot_upsert_input_type::AuthStoreSnapshotUpsertInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct UpsertAuthStoreSnapshotArgs {
pub input: AuthStoreSnapshotUpsertInput,
}
impl __sdk::InModule for UpsertAuthStoreSnapshotArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `upsert_auth_store_snapshot`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait upsert_auth_store_snapshot {
fn upsert_auth_store_snapshot(&self, input: AuthStoreSnapshotUpsertInput,
) {
self.upsert_auth_store_snapshot_then(input, |_, _| {});
}
fn upsert_auth_store_snapshot_then(
&self,
input: AuthStoreSnapshotUpsertInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<AuthStoreSnapshotProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl upsert_auth_store_snapshot for super::RemoteProcedures {
fn upsert_auth_store_snapshot_then(
&self,
input: AuthStoreSnapshotUpsertInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<AuthStoreSnapshotProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, AuthStoreSnapshotProcedureResult>(
"upsert_auth_store_snapshot",
UpsertAuthStoreSnapshotArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,28 @@
use super::*;
impl SpacetimeClient {
pub async fn resolve_npc_battle_interaction(
&self,
input: ResolveNpcBattleInteractionInput,
) -> Result<NpcBattleInteractionRecord, SpacetimeClientError> {
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
}
}

View File

@@ -0,0 +1,459 @@
use super::*;
impl SpacetimeClient {
pub async fn create_puzzle_agent_session(
&self,
input: PuzzleAgentSessionCreateRecordInput,
) -> Result<PuzzleAgentSessionRecord, SpacetimeClientError> {
let procedure_input = PuzzleAgentSessionCreateInput {
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<PuzzleAgentSessionRecord, SpacetimeClientError> {
let procedure_input = PuzzleAgentSessionGetInput {
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<PuzzleAgentSessionRecord, SpacetimeClientError> {
let procedure_input = PuzzleAgentMessageSubmitInput {
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<PuzzleAgentSessionRecord, SpacetimeClientError> {
let procedure_input = PuzzleAgentMessageFinalizeInput {
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<PuzzleAgentSessionRecord, SpacetimeClientError> {
let procedure_input = PuzzleDraftCompileInput {
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<PuzzleAgentSessionRecord, SpacetimeClientError> {
let procedure_input = PuzzleGeneratedImagesSaveInput {
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<PuzzleAgentSessionRecord, SpacetimeClientError> {
let procedure_input = PuzzleSelectCoverImageInput {
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<PuzzleWorkProfileRecord, SpacetimeClientError> {
let procedure_input = PuzzlePublishInput {
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<Vec<PuzzleWorkProfileRecord>, SpacetimeClientError> {
let procedure_input = PuzzleWorksListInput { 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<PuzzleWorkProfileRecord, SpacetimeClientError> {
let procedure_input = PuzzleWorkGetInput { 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<PuzzleWorkProfileRecord, SpacetimeClientError> {
let procedure_input = PuzzleWorkUpsertInput {
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<Vec<PuzzleWorkProfileRecord>, 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<PuzzleWorkProfileRecord, SpacetimeClientError> {
let procedure_input = PuzzleWorkGetInput { 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<PuzzleRunRecord, SpacetimeClientError> {
let procedure_input = PuzzleRunStartInput {
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<PuzzleRunRecord, SpacetimeClientError> {
let procedure_input = PuzzleRunGetInput {
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<PuzzleRunRecord, SpacetimeClientError> {
let procedure_input = PuzzleRunSwapInput {
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<PuzzleRunRecord, SpacetimeClientError> {
let procedure_input = PuzzleRunDragInput {
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<PuzzleRunRecord, SpacetimeClientError> {
let procedure_input = PuzzleRunNextLevelInput {
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
}
}

View File

@@ -0,0 +1,339 @@
use super::*;
impl SpacetimeClient {
pub async fn get_runtime_settings(
&self,
user_id: String,
) -> Result<RuntimeSettingsRecord, SpacetimeClientError> {
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_platform_browse_history(
&self,
user_id: String,
) -> Result<Vec<RuntimeBrowseHistoryRecord>, 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<RuntimeProfileDashboardRecord, SpacetimeClientError> {
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<Vec<RuntimeProfileWalletLedgerEntryRecord>, 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<RuntimeProfilePlayStatsRecord, SpacetimeClientError> {
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<Option<RuntimeSnapshotRecord>, 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<serde_json::Value>,
updated_at_micros: i64,
) -> Result<RuntimeSnapshotRecord, SpacetimeClientError> {
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<bool, SpacetimeClientError> {
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<Vec<RuntimeProfileSaveArchiveRecord>, 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 put_runtime_settings(
&self,
user_id: String,
music_volume: f32,
platform_theme: RuntimePlatformTheme,
updated_at_micros: i64,
) -> Result<RuntimeSettingsRecord, SpacetimeClientError> {
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<module_runtime::RuntimeBrowseHistoryWriteInput>,
updated_at_micros: i64,
) -> Result<Vec<RuntimeBrowseHistoryRecord>, 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<Vec<RuntimeBrowseHistoryRecord>, 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
}
}

View File

@@ -0,0 +1,100 @@
use super::*;
impl SpacetimeClient {
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<String>,
created_at_micros: i64,
) -> Result<StorySessionResultRecord, SpacetimeClientError> {
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 continue_story(
&self,
story_session_id: String,
event_id: String,
narrative_text: String,
choice_function_id: Option<String>,
updated_at_micros: i64,
) -> Result<StorySessionResultRecord, SpacetimeClientError> {
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<StorySessionStateRecord, SpacetimeClientError> {
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
}
}

View File

@@ -0,0 +1,122 @@
use crate::*;
const AUTH_STORE_SNAPSHOT_ID: &str = "default";
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
pub struct AuthStoreSnapshotRecord {
pub snapshot_json: Option<String>,
pub updated_at_micros: Option<i64>,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
pub struct AuthStoreSnapshotUpsertInput {
pub snapshot_json: String,
pub updated_at_micros: i64,
}
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
pub struct AuthStoreSnapshotProcedureResult {
pub ok: bool,
pub record: Option<AuthStoreSnapshotRecord>,
pub error_message: Option<String>,
}
#[spacetimedb::table(accessor = auth_store_snapshot)]
pub struct AuthStoreSnapshot {
#[primary_key]
pub(crate) snapshot_id: String,
pub(crate) snapshot_json: String,
pub(crate) updated_at: Timestamp,
}
// Axum 启动恢复认证状态时读取当前快照;记录不存在代表尚未产生登录态。
#[spacetimedb::procedure]
pub fn get_auth_store_snapshot(ctx: &mut ProcedureContext) -> AuthStoreSnapshotProcedureResult {
match ctx.try_with_tx(|tx| get_auth_store_snapshot_tx(tx)) {
Ok(record) => AuthStoreSnapshotProcedureResult {
ok: true,
record: Some(record),
error_message: None,
},
Err(message) => AuthStoreSnapshotProcedureResult {
ok: false,
record: None,
error_message: Some(message),
},
}
}
// Axum 每次鉴权仓储变更后覆盖写入整份快照,后续拆表阶段再替换为细粒度 reducer。
#[spacetimedb::procedure]
pub fn upsert_auth_store_snapshot(
ctx: &mut ProcedureContext,
input: AuthStoreSnapshotUpsertInput,
) -> AuthStoreSnapshotProcedureResult {
match ctx.try_with_tx(|tx| upsert_auth_store_snapshot_tx(tx, input.clone())) {
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<AuthStoreSnapshotRecord, String> {
Ok(
match ctx
.db
.auth_store_snapshot()
.snapshot_id()
.find(&AUTH_STORE_SNAPSHOT_ID.to_string())
{
Some(row) => AuthStoreSnapshotRecord {
snapshot_json: Some(row.snapshot_json),
updated_at_micros: Some(row.updated_at.to_micros_since_unix_epoch()),
},
None => AuthStoreSnapshotRecord {
snapshot_json: None,
updated_at_micros: None,
},
},
)
}
fn upsert_auth_store_snapshot_tx(
ctx: &ReducerContext,
input: AuthStoreSnapshotUpsertInput,
) -> Result<AuthStoreSnapshotRecord, String> {
let snapshot_json = input.snapshot_json.trim().to_string();
if snapshot_json.is_empty() {
return Err("认证快照 JSON 不能为空".to_string());
}
let updated_at = Timestamp::from_micros_since_unix_epoch(input.updated_at_micros);
if ctx
.db
.auth_store_snapshot()
.snapshot_id()
.find(&AUTH_STORE_SNAPSHOT_ID.to_string())
.is_some()
{
ctx.db
.auth_store_snapshot()
.snapshot_id()
.delete(&AUTH_STORE_SNAPSHOT_ID.to_string());
}
ctx.db.auth_store_snapshot().insert(AuthStoreSnapshot {
snapshot_id: AUTH_STORE_SNAPSHOT_ID.to_string(),
snapshot_json: snapshot_json.clone(),
updated_at,
});
Ok(AuthStoreSnapshotRecord {
snapshot_json: Some(snapshot_json),
updated_at_micros: Some(input.updated_at_micros),
})
}

View File

@@ -21,9 +21,11 @@ use module_quest::{
pub(crate) use serde_json::{Map as JsonMap, Value as JsonValue, json};
pub(crate) use shared_kernel::format_timestamp_micros;
pub use spacetimedb::{ProcedureContext, ReducerContext, SpacetimeType, Table, Timestamp};
use std::collections::HashSet;
mod ai;
mod asset_metadata;
mod auth;
mod big_fish;
mod domain_types;
mod entry;
@@ -32,6 +34,7 @@ mod runtime;
pub use ai::*;
pub use asset_metadata::*;
pub use auth::*;
pub use big_fish::*;
pub use domain_types::*;
pub use entry::*;
@@ -2733,10 +2736,12 @@ fn list_custom_world_work_snapshots(
validate_custom_world_works_list_input(&input).map_err(|error| error.to_string())?;
let mut items = Vec::new();
let mut active_agent_session_ids = HashSet::new();
for session in ctx.db.custom_world_agent_session().iter().filter(|row| {
row.owner_user_id == input.owner_user_id && row.stage != RpgAgentStage::Published
}) {
active_agent_session_ids.insert(session.session_id.clone());
let gate = build_custom_world_publish_gate_from_session(&session);
let draft_profile = parse_optional_session_object(session.draft_profile_json.as_deref());
let title = resolve_session_work_title(&session, draft_profile.as_ref());
@@ -2780,6 +2785,7 @@ fn list_custom_world_work_snapshots(
.custom_world_profile()
.iter()
.filter(|row| row.owner_user_id == input.owner_user_id && row.deleted_at.is_none())
.filter(|row| should_include_custom_world_profile_work(row, &active_agent_session_ids))
{
items.push(CustomWorldWorkSummarySnapshot {
work_id: format!("published:{}", profile.profile_id),
@@ -2834,6 +2840,24 @@ fn list_custom_world_work_snapshots(
Ok(items)
}
fn should_include_custom_world_profile_work(
row: &CustomWorldProfile,
active_agent_session_ids: &HashSet<String>,
) -> bool {
// 已发布 profile 是正式作品;即使来源会话还存在,也必须保留独立入口。
if row.publication_status == CustomWorldPublicationStatus::Published {
return true;
}
// 未发布 profile 若来源于仍可继续聊天的 Agent 会话,只是同一草稿的编译产物,
// works 里保留 agent_session 即可,避免草稿分组显示两份同名作品。
row.source_agent_session_id
.as_ref()
.map_or(true, |session_id| {
!active_agent_session_ids.contains(session_id)
})
}
fn get_custom_world_agent_card_detail_tx(
ctx: &ReducerContext,
input: CustomWorldAgentCardDetailGetInput,
@@ -5996,6 +6020,113 @@ mod tests {
));
}
#[test]
fn custom_world_works_hides_compiled_draft_profile_when_agent_session_is_active() {
fn build_test_custom_world_profile(
profile_id: &str,
source_agent_session_id: Option<&str>,
publication_status: CustomWorldPublicationStatus,
) -> CustomWorldProfile {
CustomWorldProfile {
profile_id: profile_id.to_string(),
owner_user_id: "user-1".to_string(),
public_work_code: if publication_status == CustomWorldPublicationStatus::Published {
Some("CW-00000001".to_string())
} else {
None
},
author_public_user_code: None,
source_agent_session_id: source_agent_session_id.map(str::to_string),
publication_status,
world_name: "潮雾列岛".to_string(),
subtitle: String::new(),
summary_text: String::new(),
theme_mode: CustomWorldThemeMode::Mythic,
cover_image_src: None,
profile_payload_json: "{}".to_string(),
playable_npc_count: 0,
landmark_count: 0,
author_display_name: "玩家".to_string(),
published_at: if publication_status == CustomWorldPublicationStatus::Published {
Some(Timestamp::from_micros_since_unix_epoch(2))
} else {
None
},
deleted_at: None,
created_at: Timestamp::from_micros_since_unix_epoch(1),
updated_at: Timestamp::from_micros_since_unix_epoch(1),
}
}
let draft_profile = build_test_custom_world_profile(
"profile-1",
Some("session-1"),
CustomWorldPublicationStatus::Draft,
);
let orphan_draft_profile = build_test_custom_world_profile(
"profile-2",
Some("session-2"),
CustomWorldPublicationStatus::Draft,
);
let published_profile = build_test_custom_world_profile(
"profile-3",
Some("session-1"),
CustomWorldPublicationStatus::Published,
);
let mut active_agent_session_ids = HashSet::new();
active_agent_session_ids.insert("session-1".to_string());
assert!(!should_include_custom_world_profile_work(
&draft_profile,
&active_agent_session_ids,
));
assert!(should_include_custom_world_profile_work(
&orphan_draft_profile,
&active_agent_session_ids,
));
assert!(should_include_custom_world_profile_work(
&published_profile,
&active_agent_session_ids,
));
}
#[test]
fn custom_world_works_keeps_compiled_draft_profile_without_active_agent_session() {
let draft_profile = CustomWorldProfile {
profile_id: "profile-1".to_string(),
owner_user_id: "user-1".to_string(),
public_work_code: None,
author_public_user_code: None,
source_agent_session_id: Some("session-1".to_string()),
publication_status: CustomWorldPublicationStatus::Draft,
world_name: "潮雾列岛".to_string(),
subtitle: String::new(),
summary_text: String::new(),
theme_mode: CustomWorldThemeMode::Mythic,
cover_image_src: None,
profile_payload_json: "{}".to_string(),
playable_npc_count: 0,
landmark_count: 0,
author_display_name: "玩家".to_string(),
published_at: None,
deleted_at: None,
created_at: Timestamp::from_micros_since_unix_epoch(1),
updated_at: Timestamp::from_micros_since_unix_epoch(1),
};
let mut active_agent_session_ids = HashSet::new();
assert!(should_include_custom_world_profile_work(
&draft_profile,
&active_agent_session_ids,
));
active_agent_session_ids.insert("session-2".to_string());
assert!(should_include_custom_world_profile_work(
&draft_profile,
&active_agent_session_ids,
));
}
#[test]
fn summarize_publish_gate_accepts_current_agent_result_schema() {
let draft_profile = serde_json::from_str::<JsonValue>(