import { assertExternalCsvConfiguration } from "../../external-model/csv/external-csv-configuration.js"; import type { ExternalCsvConfiguration } from "../../external-model/csv/external-csv-contracts.js"; import type { SerializedProjectCommand } from "./project-command.model.js"; export const externalCsvConfigurationUpdateCommandType = "external-csv-configuration.update" as const; export const externalCsvConfigurationCommandSchemaVersion = 1 as const; export interface ExternalCsvConfigurationSnapshot { id: string; projectId: string; configurationVersion: number; configuration: ExternalCsvConfiguration; } export interface ExternalCsvConfigurationUpdatePayload { expected: ExternalCsvConfigurationSnapshot | null; target: ExternalCsvConfigurationSnapshot | null; } export interface ExternalCsvConfigurationUpdateProjectCommand extends SerializedProjectCommand { schemaVersion: typeof externalCsvConfigurationCommandSchemaVersion; type: typeof externalCsvConfigurationUpdateCommandType; } export function createExternalCsvConfigurationUpdateProjectCommand( expected: ExternalCsvConfigurationSnapshot | null, target: ExternalCsvConfigurationSnapshot | null ): ExternalCsvConfigurationUpdateProjectCommand { const command: ExternalCsvConfigurationUpdateProjectCommand = { schemaVersion: externalCsvConfigurationCommandSchemaVersion, type: externalCsvConfigurationUpdateCommandType, payload: { expected, target }, }; assertExternalCsvConfigurationUpdateProjectCommand(command); return command; } export function assertExternalCsvConfigurationUpdateProjectCommand( command: SerializedProjectCommand ): asserts command is ExternalCsvConfigurationUpdateProjectCommand { if ( command.schemaVersion !== externalCsvConfigurationCommandSchemaVersion || command.type !== externalCsvConfigurationUpdateCommandType || !isRecord(command.payload) ) { throw new Error("Unsupported external CSV configuration update command."); } assertSnapshot(command.payload.expected, "expected"); assertSnapshot(command.payload.target, "target"); if (command.payload.expected === null && command.payload.target === null) { throw new Error("External CSV configuration command must change state."); } if ( command.payload.expected !== null && command.payload.target !== null && (command.payload.expected.id !== command.payload.target.id || command.payload.expected.projectId !== command.payload.target.projectId) ) { throw new Error("External CSV configuration identity must remain stable."); } } function assertSnapshot( value: unknown, field: string ): asserts value is ExternalCsvConfigurationSnapshot | null { if (value === null) { return; } if (!isRecord(value)) { throw new Error(`${field} external CSV configuration must be an object or null.`); } assertId(value.id, `${field}.id`); assertId(value.projectId, `${field}.projectId`); if (!Number.isSafeInteger(value.configurationVersion) || (value.configurationVersion as number) < 1) { throw new Error(`${field}.configurationVersion must be a positive integer.`); } assertExternalCsvConfiguration(value.configuration); if (Object.keys(value).length !== 4) { throw new Error(`${field} external CSV configuration contains unknown fields.`); } } function assertId(value: unknown, field: string) { if (typeof value !== "string" || !value.trim()) { throw new Error(`${field} must be a non-empty string.`); } } function isRecord(value: unknown): value is Record { return value !== null && typeof value === "object" && !Array.isArray(value); }