const GOVERNANCE_STATUS = Object.freeze({ draft: "draft", underApproval: "under_approval", pendingReview: "pending_review", approved: "approved", archived: "archived", returned: "returned", rejected: "rejected", quarantined: "quarantined", }); const SENSITIVITY_LEVEL = Object.freeze({ public: "public", internal: "internal", confidential: "confidential", restricted: "restricted", indexOnly: "index_only", }); const ATTACHMENT_TYPE = Object.freeze({ contractDraft: "contract_draft", contractStamped: "contract_stamped", invoice: "invoice", receipt: "receipt", quote: "quote", acceptance: "acceptance", delivery: "delivery", policyDocument: "policy_document", supportingMaterial: "supporting_material", other: "other", }); const DOWNLOAD_POLICY = Object.freeze({ standard: "standard", reasonRequired: "reason_required", restricted: "restricted", }); const GOVERNANCE_STATUS_VALUES = new Set(Object.values(GOVERNANCE_STATUS)); const SENSITIVITY_LEVEL_VALUES = new Set(Object.values(SENSITIVITY_LEVEL)); const ATTACHMENT_TYPE_VALUES = new Set(Object.values(ATTACHMENT_TYPE)); const DOWNLOAD_POLICY_VALUES = new Set(Object.values(DOWNLOAD_POLICY)); const DEFAULT_GOVERNANCE = Object.freeze({ governanceStatus: GOVERNANCE_STATUS.approved, sensitivityLevel: SENSITIVITY_LEVEL.internal, attachmentType: ATTACHMENT_TYPE.other, downloadPolicy: DOWNLOAD_POLICY.standard, }); function normalizeEnumValue(value, allowedValues, fallback) { if (typeof value !== "string") { return fallback; } const normalized = value.trim(); return allowedValues.has(normalized) ? normalized : fallback; } function normalizeGovernanceInput(input = {}, defaults = DEFAULT_GOVERNANCE) { return { governanceStatus: normalizeEnumValue(input.governanceStatus ?? input.governance_status, GOVERNANCE_STATUS_VALUES, defaults.governanceStatus), sensitivityLevel: normalizeEnumValue(input.sensitivityLevel ?? input.sensitivity_level, SENSITIVITY_LEVEL_VALUES, defaults.sensitivityLevel), attachmentType: normalizeEnumValue(input.attachmentType ?? input.attachment_type, ATTACHMENT_TYPE_VALUES, defaults.attachmentType), downloadPolicy: normalizeEnumValue(input.downloadPolicy ?? input.download_policy, DOWNLOAD_POLICY_VALUES, defaults.downloadPolicy), }; } function governanceCreateData(input = {}, defaults = DEFAULT_GOVERNANCE) { const normalized = normalizeGovernanceInput(input, defaults); return { governance_status: normalized.governanceStatus, sensitivity_level: normalized.sensitivityLevel, attachment_type: normalized.attachmentType, download_policy: normalized.downloadPolicy, }; } function mapGovernanceFields(item = {}, defaults = DEFAULT_GOVERNANCE) { const normalized = normalizeGovernanceInput({ governance_status: item.governance_status, sensitivity_level: item.sensitivity_level, attachment_type: item.attachment_type, download_policy: item.download_policy, }, defaults); return { governanceStatus: normalized.governanceStatus, sensitivityLevel: normalized.sensitivityLevel, attachmentType: normalized.attachmentType, downloadPolicy: normalized.downloadPolicy, reviewedBy: item.reviewed_by ?? null, reviewedAt: item.reviewed_at?.toISOString?.() ?? null, reviewNote: item.review_note ?? null, archivedBy: item.archived_by ?? null, archivedAt: item.archived_at?.toISOString?.() ?? null, archiveNote: item.archive_note ?? null, }; } function parseMultipartGovernanceField(part, current = {}) { if (!part || part.type !== "field") { return current; } const fieldName = part.fieldname; if (!["attachmentType", "sensitivityLevel", "governanceStatus", "downloadPolicy"].includes(fieldName)) { return current; } return { ...current, [fieldName]: typeof part.value === "string" ? part.value : "", }; } function requiresDownloadReason(attachment = {}) { const governance = normalizeGovernanceInput(attachment); return ( governance.downloadPolicy === DOWNLOAD_POLICY.reasonRequired || governance.downloadPolicy === DOWNLOAD_POLICY.restricted || governance.sensitivityLevel === SENSITIVITY_LEVEL.confidential || governance.sensitivityLevel === SENSITIVITY_LEVEL.restricted ); } function sanitizeDownloadReason(reason) { if (typeof reason !== "string") { return null; } const trimmed = reason.trim(); return trimmed ? trimmed.slice(0, 200) : null; } module.exports = { ATTACHMENT_TYPE, DEFAULT_GOVERNANCE, DOWNLOAD_POLICY, GOVERNANCE_STATUS, SENSITIVITY_LEVEL, governanceCreateData, mapGovernanceFields, normalizeGovernanceInput, parseMultipartGovernanceField, requiresDownloadReason, sanitizeDownloadReason, };