Commit Graph

5125 Commits

Author SHA1 Message Date
k88936 b83113619e 产物结构体不再派生 Debug,改成只打元数据
- server-rs/crates/platform-tripo/src/common/types.rs:TripoArtifactBytes 去掉 derive(Debug),改为手写实现,只输出 url / content_type / content_length / 字节数,几十 MB 的 bytes 不会再被一次 {:?} 刷进日志
- server-rs/crates/platform-tripo/src/common/types.rs:补用例锁住 Debug 只带字节数、不带字节内容
2026-09-24 18:00:45 +08:00
k88936 03aec35350 写明 TripoUrl 脱敏只覆盖 query 与 fragment
- server-rs/crates/platform-tripo/src/common/types.rs:redacted() 的文档注明脱敏范围只到 query / fragment,若 provider 改成把 token 写进路径(如 path-style SAS)则需一并处理路径段;无 query 分支补注释说明路径原样保留
2026-09-24 18:00:30 +08:00
k88936 925be4573d 产物扩展名兜底认下 image/jpg
- server-rs/crates/platform-tripo/src/common/types.rs:fallback_artifact_extension 补上 image/jpg 分支,非标准写法但确有 provider 这么回,预览图不再落到默认 .glb 后缀
- server-rs/crates/platform-tripo/src/common/types.rs:补用例覆盖 png / jpg / webp 与读不出形态时的 glb 兜底
2026-09-24 18:00:21 +08:00
k88936 0c716d7d9c 产物文件名主干加上长度上限
- server-rs/crates/platform-tripo/src/common/types.rs:sanitize_artifact_file_stem 在字符过滤后按 MAX_ARTIFACT_FILE_STEM_LEN=128 截断,远端来的超长主干不再拼出超过文件系统名字上限的一长串
- server-rs/crates/platform-tripo/src/common/types.rs:新建 types 的用例模块,锁住超长 / 带路径的主干被中性化并截断、全中性化后为空时退回固定名
2026-09-24 18:00:05 +08:00
k88936 2330a25172 传输判据补上 is_body,并把截断体的归因写清
- server-rs/crates/platform-tripo/src/common/error.rs:transport_error_is_transient 补上 is_body(),与 TripoError::Request.retryable 文档列举的瞬时类型对齐
- server-rs/crates/platform-tripo/src/common/error.rs:注释写明「传输中途截断的响应体在 reqwest 里落在 Decode」这一实测结论,说明为何不把 Decode 判成可重试
- server-rs/crates/platform-tripo/src/common/error.rs:补用例用截断响应体锁住 Decode 不判可重试
2026-09-24 17:59:26 +08:00
k88936 ebce5f9304 平台层转发 base_url 前去掉首尾空白
- server-rs/crates/platform-tripo/src/common/config.rs:client_options 里 base_url 先 trim 再交给 SDK,带空白的地址不再以低层解析错误的形式暴露出来
- server-rs/crates/platform-tripo/src/common/config.rs:把 client_options 的用例扩到 base_url,锁住「校验看到的」与「发出去的」是同一个值
2026-09-24 17:58:03 +08:00
k88936 80ae730dc5 平台层转发 API Key 前去掉首尾空白
- server-rs/crates/platform-tripo/src/common/config.rs:client_options 里 api_key 先 trim 再交给 SDK,校验口径与发送口径统一,带空白的密钥不再变成 provider 侧的 401
- server-rs/crates/platform-tripo/src/common/config.rs:补用例锁住 client_options 发送的 api_key 已 trim
2026-09-24 17:57:44 +08:00
k88936 b54ff06bc7 平台层 Tripo 配置把 base_url 校验成绝对 http(s) 地址
- server-rs/crates/platform-tripo/src/common/config.rs:validate 用 url::Url 解析 base_url,缺 scheme(openapi.tripo3d.com)、非 http(s)(ftp://)与无 host 的值都在构造点按 Configuration 失败,不再拖到请求期变成传输层报错
- server-rs/crates/platform-tripo/src/common/config.rs:补用例覆盖缺 scheme / 非 http(s) / 非法 URL 被拒、前后带空白的合法地址放行
2026-09-24 17:57:31 +08:00
k88936 7a4ccb8bfe 3D 产物哈希挪到 blocking 线程池
- server-rs/crates/api-server/src/tripo3d/storage.rs:上传前对最大 512 MiB 的产物做 sha256 会占住一个 Tokio worker,改成 spawn_blocking 并把 bytes 原样带回(不做整块复制),失败按 500 收口
2026-09-24 17:56:51 +08:00
k88936 f82eba4c94 3D 查价的加价累加改成溢出即报错
- server-rs/crates/api-server/src/tripo3d/pricing.rs:endpoint 查价用 checked_add 替换 saturating_add,溢出走新的 Model3dPricingError::PriceOverflow,与加载校验的 fail-closed 口径一致,不再静默夹到 u32 上限按错价收费
- server-rs/crates/api-server/src/tripo3d/pricing.rs:补用例锁住「底价 + 加价项溢出必须报错」
2026-09-24 17:55:12 +08:00
k88936 98f2c21872 3D 定价整段兜底也要过端点校验
- server-rs/crates/api-server/src/editor_generation_model3d_records.rs:记录整段缺失时回退到本地配置前先跑 endpoint.validate(),缺键分支与兜底分支走同一条 fail-closed 路径,不再依赖调用方事后补 config.validate()
- server-rs/crates/api-server/src/editor_generation_model3d_records.rs:补用例锁住「整段缺失 + 兜底配置不合法」必须被拒绝
2026-09-24 17:53:34 +08:00
k88936 a8dc0d8870 后台定价用例改键前先断言目标键存在
- server-rs/crates/api-server/src/app.rs:改默认定价 fixture 时先用 pointer_mut 断言目标键存在再赋值,不再依赖 Value::index_mut 的隐式 panic,键名或版本号漂移时报错能指出是哪一层对不上
2026-09-24 17:51:08 +08:00
k88936 f2d3e2218d 后台缺 3D 段的负例改成断言中文文案
- server-rs/crates/api-server/src/app.rs:用例文案说「必须以中文文案拒绝」,断言却只查小写英文 model3d,改成断言「定价段必须整段给出」,真正守住中文拒绝这条契约
2026-09-24 17:51:02 +08:00
k88936 40c97bf876 旧 external_generation_job 归一化用例改成真断言
- server-rs/crates/spacetime-module/src/migration.rs:provider_kind / provider_task_id 的断言改成先 as_object() 取键再比 null,原先用 Value 索引在键缺失时返回 Null,归一化被删掉也照样通过
2026-09-24 17:48:41 +08:00
k88936 14294a2c9b 修掉多视图生成 3D 请求文档注释里的漏字
- server-rs/crates/shared-contracts/src/model3d/multiview_to_model/request.rs:公开文档注释「多视图生 3D」补回漏字,改成「多视图生成 3D」
2026-09-24 17:46:54 +08:00
k88936 82e889dc6d 带地址响应体的过滤改成大小写不敏感
- server-rs/crates/platform-tripo/src/common/error.rs:body_snippet 先整串转小写再匹配 http:// 与 https://,`HTTPS://…` 这类大小写变体不再绕过过滤,签名 URL 不会被带进持久化的任务错误信息
2026-09-24 17:44:20 +08:00
k88936 79ae24fa43 3D 产物的 content type 与落库值同源
- server-rs/crates/api-server/src/tripo3d/storage.rs:返回给调用方的 content_type 改为优先取 HEAD 复核回来的值(取不到才回落到本地解析值),与 asset_object.content_type 用同一份取值。此前接口返回的是本地解析值、落库的是 OSS 回显值,OSS 一旦归一化或回显空值,两个来源就会给出互相矛盾的元数据
2026-09-24 17:43:52 +08:00
k88936 8af4287bf3 落点校验的文档注释改成与实现一致
- server-rs/crates/api-server/src/tripo3d/validation.rs:validate_target 的注释此前写「项目资源与素材库二选一 / 不接受两个都给」,与实际实现(两个都接受、只要求至少一个)以及用例 target_accepts_both_locators_but_requires_at_least_one 矛盾,改为按实际口径描述
2026-09-24 17:43:43 +08:00
k88936 791011eacf 落点纵深防御的兜底字段名与归因口径对齐
- server-rs/crates/api-server/src/tripo3d/target.rs:两个落点都没给时的兜底报错由点 projectId 改为点 target,与 target_unavailable_field 对 both-missing 的归因一致,不再把错误指到一个调用方可能根本没传的键上
2026-09-24 17:43:36 +08:00
k88936 d927a8cfa7 后台保存定价的版本推进改为饱和加法
- server-rs/crates/api-server/src/state.rs:expected_updated_at_micros 来自后台请求体、只校验了必须给出,没有范围校验;expected + 1 在 i64::MAX 上会溢出(debug 下 panic、release 下回绕成 i64::MIN 并让版本推进失效),改用 saturating_add(与测试分支同一口径)
2026-09-24 17:43:32 +08:00
k88936 0b3c15ee7c 图生 3D 的源图对象键为空时按缺失处理
- server-rs/crates/api-server/src/tripo3d/image_source.rs:预检对 object_key 加非空判断,空串 / 纯空白与缺字段同义。此前 Some("") 能过预检,等任务已入队计费后才在下载源图时失败
2026-09-24 17:43:24 +08:00
k88936 643ffedfb6 provider 4xx 不再把原文错误体回给客户端
- server-rs/crates/api-server/src/tripo3d/errors.rs:400..=499 分支不再拼接 error.to_string()。TripoError::Api 的 Display 直接转述 provider 的 code/message/suggestion(HTTP 错误体原文,未做 URL 清洗),可能把带签名的地址等内部信息带进用户可见的任务错误;改为固定中文文案
2026-09-24 17:43:17 +08:00
k88936 72cdabbef3 定点引用查询补上调用方必须传本人 user_id 的说明
- server-rs/crates/api-server/src/editor_project.rs:resolve_editor_reference_record_by_id_for_owner 从 pub 收窄到 pub(crate) 后授权边界移到调用方,给函数补上「必须传已认证用户自己的 ID,本函数不做授权」的前置条件说明,避免后续 crate 内调用方传入客户端可控的 owner 造成越权读取
2026-09-24 17:43:13 +08:00
k88936 110354fad9 请求路径也拦住写歪的 Tripo 网关地址
- server-rs/crates/api-server/src/tripo3d/provider.rs:URL 判据(合法 URL + HTTP(S) + 有主机名)抽成 validate_tripo_base_url_syntax,启动期门禁与 tripo_settings 共用;非空但缺 scheme / 非 HTTP(S) / 无主机名的地址在请求前就映射 503,不再拖到 SDK 里变成一条指向连接失败的报错
- server-rs/crates/api-server/src/tripo3d/provider.rs:补请求期拒绝写歪地址的用例
2026-09-24 17:38:28 +08:00
k88936 62600fe881 请求路径也拦住越界的 TRIPO_RETRIES
- server-rs/crates/api-server/src/tripo3d/provider.rs:tripo_settings 显式校验 config.tripo_retries 不超过 TRIPO_MAX_RETRIES 并映射 503。TripoSettings::validate 只查空值与零超时,越界值会原样进 artifact_retries,把产物下载的挂起时间成倍拉长;注释里「第二道防线」的说法此前并不成立
- server-rs/crates/api-server/src/tripo3d/provider.rs:补越界拒绝 / 上限放行的用例
2026-09-24 17:36:55 +08:00
k88936 1600c107e0 修掉没测到 API Key 分支的用例
- server-rs/crates/api-server/src/tripo3d/provider.rs:missing_api_key_is_reported_as_unavailable 先补全 TRIPO_BASE_URL 再断言缺密钥。AppConfig::default() 的网关是空串,原用例一直停在「缺网关」分支上,API Key 校验删掉也能过
2026-09-24 17:35:45 +08:00
k88936 2877ede719 3D 面板的栅格覆盖不再依赖规则先后顺序
- src/index.css:`--model3d` 面板的 grid/width/gap 覆盖把 `--image` 一起写进选择器提高特异性。它与 `--image` 的声明特异性相同,此前只靠 `--model3d` 排在后面取胜,规则顺序一变就会退回两栏布局
2026-09-24 17:33:25 +08:00
k88936 0d2c81a3ce 画布导出的目录名单一来源
- src/components/image-editor/useImageCanvasAssetExportWorkflow.ts:images / media / 3d_models 三个目录名提成 EXPORT_FOLDER 常量,建目录、挑目录与按层分流共用同一份字面量(写错目录名不会编译报错,只会在 zip 里悄悄换目录)
2026-09-24 17:33:02 +08:00
k88936 9c2a9383fc 3D 两个生成模式也随失焦与关闭收起面板
- src/components/image-editor/ImageCanvasGenerationDialogModel.ts:hideGeneratedLayerComposerAfterBlur 与 closeGenerateComposerDialog 的模式清单补上 model3d-text-to-model / model3d-image-to-model,此前点空白画布或关闭操作都收不起 3D 面板(其它生成模式都能收起)
- src/components/image-editor/ImageCanvasGenerationDialogModel.test.ts:补两个 3D 模式的收起断言
2026-09-24 17:32:39 +08:00
k88936 946c101630 画布没接住任务状态时按失败收口
- src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts:applyQueuedGeneration 返回 false 时不再静默复位成 idle(用户会以为没提交过、再点一次就是又一次已扣费的外部生成),改为写回失败态与明确文案
- src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts:新增 MODEL3D_QUEUE_HANDOFF_FAILED_MESSAGE,与「服务端没返回任务状态」区分开
- src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx:原「回到空闲态」用例改为断言失败态
2026-09-24 17:32:13 +08:00
k88936 3455b7a00f 3D 提交失败路径也刷新钱包余额
- src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts:请求失败与「2xx 但没有任务状态」两条路径都调用 onWalletBalanceMayHaveChanged,与其它画布生成链路的 runEditorGenerationWithWalletRefresh 同一口径(超时或空 body 的 2xx 都可能已经扣费)
- src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx:补两条失败路径各刷新一次钱包的断言
2026-09-24 17:31:28 +08:00
k88936 5ba7a993de 3D 提交编排整段落在错误边界内
- src/components/image-editor/model3d-generation/useModel3dGenerationTask.ts:把取占位框、算结果标题与构造提交计划一并移进 try,注入的回调或老快照缺字段导致的抛错不再漏成未捕获 rejection,而是照常写回失败态与提示
- src/components/image-editor/model3d-generation/useModel3dGenerationTask.test.tsx:补「计划构造阶段抛错」的用例(缺 prompt 的老快照)
2026-09-24 17:30:53 +08:00
k88936 2350c56f2f 3D 失败提示只透出服务端给的文案
- src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts:resolveModel3dGenerationErrorMessage 只对 ApiClientError 原样透出 message;原生 SyntaxError(2xx 但 body 不是 JSON)与其它运行时 TypeError 的英文技术文案不再直接显示给用户
- src/components/image-editor/model3d-generation/Model3dGenerationSubmission.test.ts、useModel3dGenerationTask.test.tsx:用例改用 ApiClientError 构造服务端文案,并补非服务端错误退回兜底文案的断言
2026-09-24 17:30:01 +08:00
k88936 96b52ae7ee 提交计划把非图生模式显式判为不支持
- src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts:图生分支之后补显式模式判断,契约将来新增端点时直接失败关闭,而不是静默按文生请求发出、丢掉新端点的输入
2026-09-24 17:28:46 +08:00
k88936 8d17855133 提交计划去掉无人读取的 title 字段
- src/components/image-editor/model3d-generation/Model3dGenerationSubmission.ts:Model3dSubmissionPlanBase.title 没有任何消费方(调用方自己按 resolveModel3dResultTitle 重算),删除该字段与它的装配代码,避免把死数据当成权威标题
2026-09-24 17:28:29 +08:00
k88936 bc68a9e884 查看器未知失败原因退回兜底文案
- src/components/image-editor/model3d-preview/Model3dViewerModel.ts:default 分支保留 `never` 的编译期穷尽检查,但运行时(宿主与查看器版本错配)改回 fallbackText,不再把原始原因码当用户文案显示
2026-09-24 17:28:02 +08:00
k88936 7b8bbac098 报价缺价文案提成具名常量
- src/components/image-editor/model3d-generation/Model3dGenerationFormModel.ts:底价缺失与加价项缺失两句文案按模块既有约定提成 MODEL3D_PRICING_MISSING_BASE_PRICE_REASON 与 resolveModel3dPricingMissingAddOnReason,不再散落在计算路径里
2026-09-24 17:27:37 +08:00
k88936 fe44054aa2 退役模型版本在报价与提交路径上一起回落默认版本
- src/components/image-editor/model3d-generation/Model3dGenerationFormModel.ts:resolveModel3dModelVersion 改为走 normalizeModel3dModelVersion,老快照里契约中已不存在的版本不再直接进 MODEL3D_MODEL_TABLE 查表(原来会抛异常),报价与提交体也不会分裂成两个版本;此前该归一化函数只有测试在用
- src/components/image-editor/model3d-generation/Model3dGenerationFormModel.test.ts:补 resolveModel3dModelVersion 收到退役版本的用例
2026-09-24 17:27:17 +08:00
k88936 9840f17189 模型版本判据不再认下原型链上的键
- src/components/image-editor/model3d-generation/Model3dGenerationValidation.ts:isModel3dModelVersion 改用 Object.hasOwn,`toString` / `__proto__` 这类继承键不再被判成契约版本(之后查表会拿到 undefined)
- src/components/image-editor/model3d-generation/Model3dGenerationFormModel.test.ts:补原型链键回落默认版本的用例
2026-09-24 17:26:49 +08:00
k88936 3191ca9d89 3D 面板的重试代次改在点击时铸造
- src/components/image-editor/model3d-generation/Model3dGenerationModal.tsx:失败态下的代次刷新由渲染体里的常量改为点击时调用的 resolveSubmitDialog(),提交键不再随每次重渲染(含 StrictMode 双渲染)变化,渲染保持纯函数
2026-09-24 17:26:17 +08:00
k88936 cd5218535e 3D 面板参考图菜单的边界 refs 数组稳定下来
- src/components/image-editor/model3d-generation/Model3dGenerationModal.tsx:boundaryRefs 用 useMemo 缓存,避免每次渲染都新建数组导致浮层 dismiss effect 反复解绑/重挂 document 监听
2026-09-24 17:26:02 +08:00
k88936 89b8211b94 生成中禁用图生 3D 参考图的删除按钮
- src/components/image-editor/model3d-generation/Model3dGenerationForm.tsx:已选参考图槽位补 disabled={disabled},提交中不再能删掉这次请求用的参考图,与面板其余控件的禁用口径一致
2026-09-24 17:25:37 +08:00
k88936 fb0be97609 图生 3D 的素材库空确认不再清掉已选参考图
- src/components/image-editor/ImageCanvasGenerationDialogModel.ts:单槽对话框只在素材库确实选到了图时才做「替换」,空确认退回原行为(保留画布点选/上传的那张)。此前确认按钮不校验空选,空确认会把已有参考图直接清掉
- src/components/image-editor/projectAssetReferencePickerModel.test.ts:补空确认保留画布参考图的用例
2026-09-24 17:25:16 +08:00
k88936 5d68749534 查看器不再把 glTF 解析失败吞成「未知错误」
- packages/model3d-viewer/src/loader.ts:GLTFLoader 的 onError 回传 ErrorEvent,改为先取它的 message 再包成 Error 抛出,外层报错能带出真实解析原因,而不是退化成「未知错误」
2026-09-24 17:24:40 +08:00
k88936 61cfb8800d 查看器认得 ASCII FBX 的字节开头
- packages/model3d-viewer/src/loader.ts:字节魔数多认一种 ASCII FBX 开头(`; FBX`,Blender 等工具的默认导出),此前这批文件在没显式给 format 时会被判 unsupported-format,尽管 FBXLoader 能解析
- packages/model3d-viewer/src/loader.ts:BOM / 前导空白的跳过抽成 resolveModel3dViewerContentStart,JSON 与 ASCII FBX 两处判据共用
- packages/model3d-viewer/src/loader.test.ts:补 ASCII FBX(含前导空白)的字节判定用例
2026-09-24 17:24:28 +08:00
k88936 0c0819249d 查看器取景装配失败时释放 renderer 与模型资源
- packages/model3d-viewer/src/scene.ts:模型加载成功后的取景 / ResizeObserver / 渲染循环装配抽成 setupLoadedScene,由外层 try/catch 兜住;任何异常先 teardown 再抛出,避免调用方拿不到 scene 引用时漏掉 WebGL 上下文与模型 GPU 资源
2026-09-24 17:23:58 +08:00
k88936 55ce6d7129 取景距离抬到不会让轨道缩放范围颠倒的下限
- packages/model3d-viewer/src/framing.ts:computeModel3dViewerFitDistance 对调用方传入的距离加下限(radius × 0.2 / 8),避免 distance 过小时 maxDistance 小于 minDistance,取景与轨道钳制同时失效
- packages/model3d-viewer/src/framing.test.ts:补极小距离的下限用例
2026-09-24 17:23:31 +08:00
k88936 3624f454e2 取景视角限定在 (0, 180),非法值回落到默认视角
- packages/model3d-viewer/src/framing.ts:新增 normalizeFovDegrees,fovDegrees 只在 (0, 180) 内采用,>=180 时 tan(halfFovY) 非正会把 limitY/limitX 与 fallbackDistance 算成 0 或负数,污染取景距离与 near/far
- packages/model3d-viewer/src/framing.test.ts:补 180 / 360 / 0 / 负数 / NaN 回落到默认视角的用例
2026-09-24 17:23:19 +08:00
k88936 e5076eb27c 契约绑定生成脚本改用能命中的过滤器
- package.json:contracts:model3d:generate 的过滤器由 `model3d editor_canvas` 改为工作区文档写明的 `export_bindings`;ts-rs 生成的用例名是 `export_bindings_<类型名小写>`,`editor_canvas` 带下划线永远匹配不到 editor-canvas 两个绑定,此前脚本实际只重生成 model3d 一侧
2026-09-24 17:21:47 +08:00
k88936 62e6bfc52f 后台 3D 定价两栏底价输入改为描述表驱动
- apps/admin-web/src/pages/AdminEditorGenerationModel3dPricingSection.tsx:抽出 VERSION_PRICE_FIELDS 描述表,无贴图 / 带贴图两栏共用一段 JSX,字段键与展示名只有一处来源,避免两栏后续改动走偏
2026-09-24 17:20:42 +08:00