推进 SpacetimeDB adapter 与 client 收口

This commit is contained in:
2026-04-29 16:53:54 +08:00
parent f82775b852
commit 62934b0809
17 changed files with 1023 additions and 597 deletions

View File

@@ -18,7 +18,7 @@ use module_puzzle::{
};
use serde_json::from_str as json_from_str;
use serde_json::to_string as json_to_string;
use spacetimedb::{ProcedureContext, Table, Timestamp, TxContext};
use spacetimedb::{ProcedureContext, SpacetimeType, Table, Timestamp, TxContext};
/// 拼图 Agent session 真相表。
/// 当前只保存结构化字段与 JSON 草稿,不提前拆出更多编辑态子表。
@@ -84,6 +84,33 @@ pub struct PuzzleWorkProfileRow {
published_at: Option<Timestamp>,
}
/// 拼图创作事件类型。
///
/// 事件表只广播跨层订阅需要的轻量事实,作品真相仍以
/// `puzzle_work_profile` 和 `puzzle_agent_session` 为准。
#[derive(Clone, Copy, Debug, PartialEq, Eq, SpacetimeType)]
pub enum PuzzleEventKind {
WorkPublished,
}
#[spacetimedb::table(
accessor = puzzle_event,
public,
event,
index(accessor = by_puzzle_event_profile_id, btree(columns = [profile_id])),
index(accessor = by_puzzle_event_owner_user_id, btree(columns = [owner_user_id]))
)]
pub struct PuzzleEvent {
#[primary_key]
event_id: String,
profile_id: String,
work_id: String,
session_id: Option<String>,
owner_user_id: String,
event_kind: PuzzleEventKind,
occurred_at: Timestamp,
}
/// 运行态 run 快照表。
#[spacetimedb::table(
accessor = puzzle_runtime_run,
@@ -869,6 +896,7 @@ fn publish_puzzle_work_tx(
updated_at: Timestamp::from_micros_since_unix_epoch(input.published_at_micros),
},
);
emit_puzzle_work_published_event(ctx, &profile, input.published_at_micros);
Ok(profile)
}
@@ -1543,6 +1571,25 @@ fn upsert_puzzle_work_profile(ctx: &TxContext, profile: PuzzleWorkProfile) -> Re
Ok(())
}
fn emit_puzzle_work_published_event(
ctx: &TxContext,
profile: &PuzzleWorkProfile,
occurred_at_micros: i64,
) {
ctx.db.puzzle_event().insert(PuzzleEvent {
event_id: format!(
"pzevt_{}_{}_published",
profile.profile_id, occurred_at_micros
),
profile_id: profile.profile_id.clone(),
work_id: profile.work_id.clone(),
session_id: profile.source_session_id.clone(),
owner_user_id: profile.owner_user_id.clone(),
event_kind: PuzzleEventKind::WorkPublished,
occurred_at: Timestamp::from_micros_since_unix_epoch(occurred_at_micros),
});
}
fn insert_puzzle_runtime_run(
ctx: &TxContext,
run: &PuzzleRunSnapshot,