补强静态发布安全边界

This commit is contained in:
2026-08-10 18:27:53 +08:00
parent 4df047708b
commit 8dd99c1855
15 changed files with 560 additions and 85 deletions

View File

@@ -68,6 +68,7 @@ function buttonLabel(phase: PublishPhase): string {
export function ProjectPublishAction({ project, projectType }: ProjectPublishActionProps) {
const [phase, setPhase] = useState<PublishPhase>('idle');
const [failure, setFailure] = useState<WorksPublishFailure | null>(null);
const [bindingWarning, setBindingWarning] = useState<string | null>(null);
const pollGeneration = useRef(0);
useEffect(() => () => {
@@ -130,6 +131,7 @@ export function ProjectPublishAction({ project, projectType }: ProjectPublishAct
pollGeneration.current += 1;
const generation = pollGeneration.current;
setFailure(null);
setBindingWarning(null);
setPhase('submitting');
try {
@@ -138,6 +140,7 @@ export function ProjectPublishAction({ project, projectType }: ProjectPublishAct
project: metadata,
});
if (pollGeneration.current !== generation) return;
setBindingWarning(result.bindingWarning?.message ?? null);
setPhase('polling');
void pollBuildStatus(result.upload.version_id, generation);
} catch (error) {
@@ -185,6 +188,16 @@ export function ProjectPublishAction({ project, projectType }: ProjectPublishAct
</p>
) : null}
{bindingWarning ? (
<p
data-testid="project-publish-binding-warning"
aria-live="polite"
className="max-w-md rounded-xl border border-amber-500/30 bg-amber-50 px-3 py-2 text-left text-xs leading-5 text-amber-900"
>
{bindingWarning}
</p>
) : null}
{failure ? (
<div
data-testid="project-publish-failure"

View File

@@ -135,9 +135,15 @@ export type WorksProjectSourcePublishInput = {
project: WorksProjectMetadataInput;
};
export type WorksSubmissionBindingWarning = {
code: 'LOCAL_PREVIEW_BINDING_SAVE_FAILED';
message: string;
};
export type WorksProjectSourcePublishResult = {
package: WorksStaticPackageSummary;
upload: WorksProjectVersionUpload;
bindingWarning?: WorksSubmissionBindingWarning;
};
export type WorksSpeechTranscription = {
@@ -416,6 +422,7 @@ export async function publishWorksProjectSource(
error?: string;
package?: WorksStaticPackageSummary;
upload?: WorksProjectVersionUpload;
binding_warning?: unknown;
}>('/api/works/projects/publish-source', {
method: 'POST',
body: JSON.stringify({
@@ -430,7 +437,18 @@ export async function publishWorksProjectSource(
response.code,
);
}
return { package: response.package, upload: response.upload };
const bindingWarning = isRecord(response.binding_warning)
&& response.binding_warning.code === 'LOCAL_PREVIEW_BINDING_SAVE_FAILED'
? {
code: 'LOCAL_PREVIEW_BINDING_SAVE_FAILED' as const,
message: '已提交云端,但本机预览绑定保存失败;可重新打开项目/重新提交。',
}
: undefined;
return {
package: response.package,
upload: response.upload,
...(bindingWarning ? { bindingWarning } : {}),
};
}
export async function fetchWorksProjectVersions(