Release govoplan-campaign v0.1.28: stabilize saving, review and delivery recovery
Module Package Release / publish-packages (push) Successful in 12s

This commit is contained in:
2026-09-08 01:32:26 +02:00
parent 1b32427813
commit c51fc180fb
111 changed files with 6905 additions and 980 deletions
@@ -1,5 +1,9 @@
import { campaignJsonForAttachmentPreview } from "../src/features/campaigns/utils/templatePreviewDraft";
import { checkContentLibraryCompatibility } from "../src/features/campaigns/utils/contentLibraryCompatibility";
import {
campaignVersionUpdateForRequest,
clientCampaignEditorState
} from "../src/features/campaigns/utils/editorState";
function assert(condition: unknown, message = "assertion failed"): void {
if (!condition) throw new Error(message);
@@ -68,3 +72,44 @@ const compatibility = checkContentLibraryCompatibility([
assert(!compatibility.compatible, "missing or wrong-typed fields are incompatible");
assert(compatibility.missing.length === 1 && compatibility.missing[0].path === "global:case_reference", "namespaced missing fields are normalized");
assert(compatibility.incompatible.length === 1 && compatibility.incompatible[0].actual === "boolean", "type mismatches are reported");
// Ordinary saves must not echo the server-owned evidence returned by reads.
// This is the state that previously broke saves when leaving the Template page.
const loadedEditorState = {
created_from: "minimal_campaign",
field_overrides: { department: false },
opt_ins: { inline_guidance: true },
review_send: {
inspection_complete: true,
reviewed_message_keys: ["gabriele.fode", "fruzsina.molnar-gabor"],
issue_decisions: [],
updated_at: "2026-07-15T11:23:31.569257+00:00",
updated_by_user_id: "064fa105-9e69-4f29-8558-a7665eb219df"
},
approval_gate: { request_id: "approval-1", requested_by_user_id: "approver-1" },
smtp: { password: "legacy-secret" }
};
const clientState = clientCampaignEditorState(loadedEditorState);
assert(JSON.stringify(clientState) === JSON.stringify({
created_from: "minimal_campaign",
field_overrides: { department: false },
opt_ins: { inline_guidance: true }
}), "draft and merge metadata contains only client-owned fields");
const savePayload = {
editor_state: loadedEditorState,
base_revision: 7,
campaign_json: { template: { subject: "Updated template" } },
migrate_legacy_mail_settings: true
};
const requestPayload = campaignVersionUpdateForRequest(savePayload);
assert(JSON.stringify(requestPayload.editor_state) === JSON.stringify(clientState), "save, autosave, and fork requests omit review and approval evidence");
assert(!JSON.stringify(requestPayload).includes("legacy-secret"), "unknown legacy metadata is not resubmitted");
assert(requestPayload.base_revision === 7 && requestPayload.migrate_legacy_mail_settings, "concurrency and explicit migration controls are preserved");
assert(requestPayload.campaign_json === savePayload.campaign_json, "campaign content is not rewritten by metadata serialization");
assert(savePayload.editor_state.review_send.inspection_complete, "read response evidence is not mutated");
assert("approval_gate" in savePayload.editor_state, "read response approval evidence is preserved");
assert(Object.keys(clientCampaignEditorState(undefined)).length === 0, "new drafts need no metadata");
const omittedEditorState = { base_revision: 2, editor_state: undefined };
assert(campaignVersionUpdateForRequest(omittedEditorState) === omittedEditorState, "omitted metadata remains omitted");
const nullEditorState = { editor_state: null };
assert(campaignVersionUpdateForRequest(nullEditorState) === nullEditorState, "null metadata retains its unchanged-state semantics");