内容与注册表指纹拆成两条命令,指纹退出内容 DTO

- read_xhs_minitool_export 只回内容(form + hasScript),新增 read_xhs_minitool_export_hash 单独回注册表指纹;save_xhs_minitool_export_form 成功后回新的指纹。
- XHSMiniToolExportState 去掉 contentHash:它是写回时的同步细节,混在「面板渲染的内容」里会让自动刷新顺手换掉写回基线,把两次刷新之间的外部改动认成自己的基线、静默吞掉冲突。
- 分两条命令之后,刷新这条高频路径在类型上就碰不到基线;指纹只在进编辑会话或重读到的内容真的被采纳时取一次。
- 待办标注:这条命令切分也让「面板不再显示任何同步状态」在类型上成立(前端不必拿到指纹就能渲染)。
This commit is contained in:
2026-10-05 18:28:12 +08:00
parent 6dd0dc00cc
commit f7be3e6a11
4 changed files with 32 additions and 20 deletions
@@ -8,7 +8,8 @@ use client_extensions::*;
use environment_check::preflight_web_game_creation;
use error_report::*;
use export::draft::xhs_minitool::commands::{
read_xhs_minitool_export, run_xhs_minitool_export_build, save_xhs_minitool_export_form,
read_xhs_minitool_export, read_xhs_minitool_export_hash, run_xhs_minitool_export_build,
save_xhs_minitool_export_form,
};
use game_distribution_publish::*;
use plugin_host::{
@@ -689,6 +690,7 @@ pub(super) fn run() {
create_local_project_checkpoint,
export_local_project_package,
read_xhs_minitool_export,
read_xhs_minitool_export_hash,
save_xhs_minitool_export_form,
run_xhs_minitool_export_build,
prepare_local_project_game_package,
@@ -1,8 +1,12 @@
//! 导出面板用到的三个 `#[tauri::command]`。
//! 导出面板用到的四个 `#[tauri::command]`。
//!
//! 每个命令只做一件事,全部走 typed 失败([`XHSMiniToolExportError`])。没有项目写锁、不推进
//! revision:宿主在这里读写的,就是 `.export/` 下那一个注册表文件。
//!
//! 「内容」与「注册表指纹」是两条命令:[`read_xhs_minitool_export`] 是面板自动刷新反复调的
//! 那条,拿不到指纹;指纹(写回时的 `baseHash`)只在进编辑会话、或内容真的被采纳时单独取一次。
//! 分开是为了让刷新动作在类型上就动不了写回基线——否则外部改动会被静默吞掉。
//!
//! 入参在 JS 侧是 camelCase(Tauri 的既有口径):`projectPath`、`baseHash`。
use std::path::{Path, PathBuf};
@@ -13,16 +17,27 @@ use super::registry::{self, RegistrySnapshot};
use super::validation::validate_form;
use super::{build, script};
/// 读现场:注册表(缺则补一份空表单)+ 脚本是否存在。
/// 读内容:注册表(缺则补一份空表单)+ 脚本是否存在。自动刷新反复调的就是这一条。
#[tauri::command]
pub(crate) async fn read_xhs_minitool_export(
project_path: String,
) -> Result<XHSMiniToolExportState, XHSMiniToolExportError> {
let root = project_root(&project_path)?;
Ok(state(&root, registry::load(&root)?))
Ok(content(&root, registry::load(&root)?))
}
/// 保存表单:先硬校验(首个错误即返回),再按 `base_hash` 判冲突。
/// 读注册表指纹:写回时原样带回做冲突判据。
///
/// 单独一条命令,且**只在内容被采纳时**取:让「刷新」这条高频路径在类型上碰不到写回基线。
#[tauri::command]
pub(crate) async fn read_xhs_minitool_export_hash(
project_path: String,
) -> Result<String, XHSMiniToolExportError> {
let root = project_root(&project_path)?;
Ok(registry::load(&root)?.content_hash)
}
/// 保存表单:先硬校验(首个错误即返回),再按 `base_hash` 判冲突;成功后回新的指纹。
///
/// 校验挡在保存之前是刻意的——平台字数与 icon 限制是硬约束,让它在用户输入时就被看见,比等到
/// 人工上传被平台打回便宜。
@@ -31,10 +46,10 @@ pub(crate) async fn save_xhs_minitool_export_form(
project_path: String,
form: XHSMiniToolExportForm,
base_hash: String,
) -> Result<XHSMiniToolExportState, XHSMiniToolExportError> {
) -> Result<String, XHSMiniToolExportError> {
let root = project_root(&project_path)?;
validate_form(&root, &form)?;
Ok(state(&root, registry::save(&root, &form, &base_hash)?))
Ok(registry::save(&root, &form, &base_hash)?.content_hash)
}
/// 跑一次导出:每次都重新执行项目脚本、重新产出 zip。
@@ -47,11 +62,10 @@ pub(crate) async fn run_xhs_minitool_export_build(
}
/// `hasScript` 永远现算:注册表里不存、也不缓存这个事实。
fn state(root: &Path, snapshot: RegistrySnapshot) -> XHSMiniToolExportState {
fn content(root: &Path, snapshot: RegistrySnapshot) -> XHSMiniToolExportState {
XHSMiniToolExportState {
form: snapshot.form,
has_script: script::find(root).is_some(),
content_hash: snapshot.content_hash,
}
}
@@ -52,10 +52,11 @@ pub(crate) enum XHSMiniToolExportField {
IconPath,
}
/// 面板读到的现场状态。
/// 面板读到的现场内容。
///
/// 没有「产物是否已存在」:每次导出都重新构建。也没有 status / 已适配标记——「有没有脚本」
/// 永远从 npm 包的 `package.json` 现算,不落盘。
/// 永远从 npm 包的 `package.json` 现算,不落盘。也没有注册表指纹:那是写回时的同步细节,
/// 由 `read_xhs_minitool_export_hash` 单独给,自动刷新读的这条命令碰不到它。
#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/view/project-development/export/generated/"))]
@@ -63,8 +64,6 @@ pub(crate) struct XHSMiniToolExportState {
pub(crate) form: XHSMiniToolExportForm,
/// `scripts["build:xhs-minitool"]` 是否存在。
pub(crate) has_script: bool,
/// 注册表文件的当前内容指纹。保存时原样带回做冲突判据;它不写进文件。
pub(crate) content_hash: String,
}
/// 一次成功导出的结果。产物路径是常量(`.export/xhs-minitool.zip`),不进 DTO。
@@ -2,17 +2,14 @@
import type { XHSMiniToolExportForm } from "./XHSMiniToolExportForm";
/**
* 面板读到的现场状态。
* 面板读到的现场内容。
*
* 没有「产物是否已存在」:每次导出都重新构建。也没有 status / 已适配标记——「有没有脚本」
* 永远从 npm 包的 `package.json` 现算,不落盘。
* 永远从 npm 包的 `package.json` 现算,不落盘。也没有注册表指纹:那是写回时的同步细节,
* 由 `read_xhs_minitool_export_hash` 单独给,自动刷新读的这条命令碰不到它。
*/
export type XHSMiniToolExportState = { form: XHSMiniToolExportForm,
/**
* `scripts["build:xhs-minitool"]` 是否存在。
*/
hasScript: boolean,
/**
* 注册表文件的当前内容指纹。保存时原样带回做冲突判据;它不写进文件。
*/
contentHash: string, };
hasScript: boolean, };