import { getAuthedConvexClient } from "@/lib/convex/route"; import { type CommandEnvelope, type BridgeContext, } from "@/lib/documents/bridge"; import { recordBridgeCommandFailureArtifacts, recordRustBridgeCommandArtifacts, } from "@/lib/documents/bridge-log"; import type { DocumentSavePayload } from "@/lib/documents/save-contract"; import { DocumentBridgeError } from "@/lib/documents/bridge"; import { executeRustBridgeMutationTransport, resolveRustBridgeCommandPlan, } from "@/lib/documents/rust-runtime"; export type DocumentSaveExecutionResult = { requestId: string; traceId: string; commandId: string; commandName: string; revision: number | null; conflictDetectionKey: string | null; }; export async function executeSaveBridgeCommand(input: { context: BridgeContext; envelope: CommandEnvelope; }): Promise { const { client } = await getAuthedConvexClient(); const plan = await resolveRustBridgeCommandPlan({ context: input.context, envelope: input.envelope, }); let mutationResult; try { mutationResult = await executeRustBridgeMutationTransport<{ revision?: number | null; conflict_detection_key?: string | null; }>({ client, plan, }); } catch (error) { await recordBridgeCommandFailureArtifacts({ client, context: input.context, envelope: input.envelope, error, }); if (error instanceof Error && /正文(内容已变更|冲突检测失败)/.test(error.message)) { throw new DocumentBridgeError(error.message, 409, "REJECTED", { reason: "content_conflict", revision: input.envelope.payload.revision, conflictDetectionKey: input.envelope.payload.conflictDetectionKey, }); } throw error; } await recordRustBridgeCommandArtifacts({ client, context: input.context, envelope: input.envelope, plan, result: mutationResult, }); return { requestId: input.context.requestId, traceId: input.context.traceId, commandId: input.envelope.commandId, commandName: input.envelope.name, revision: typeof mutationResult?.revision === "number" && Number.isInteger(mutationResult.revision) ? mutationResult.revision : null, conflictDetectionKey: typeof mutationResult?.conflict_detection_key === "string" && mutationResult.conflict_detection_key.trim() ? mutationResult.conflict_detection_key : null, }; }