/** * Type ตรงกับ response ของ backend (`Models/VersionDtos.cs` — ASP.NET Core serialize camelCase) * พอร์ตดิบจาก D:\word-addin-poc\addin\src\models\versionRecord.ts */ /** response ของ POST /api/documents/{documentId}/versions */ export interface UploadVersionResult { hasPdf: boolean; versionId: string; versionNumber: number; } /** field เดียวใน snapshot ของ version (เอกสารที่ผูก template) */ export interface FieldSnapshotEntry { value: string; missing: boolean; } /** fields ของ version รูปแบบปัจจุบัน — **ก้อนเดียวกับ return ของ `/api/template/extract`** * ที่ server แกะจากไฟล์ .docx ฝั่ง server ตอนอัปโหลด (2026-10-30) · ค่าวันที่ใน * properties มาเป็น ISO string ตาม DTO ของกลุ่ม docver */ export interface ExtractSnapshotFields { /** ค่า Content Control `{ [tag]: text }` */ cc: Record; /** ข้อความใน bookmark `{ [name]: text }` */ bookmark: Record; /** document properties (standard/extended/custom) */ properties: { standard?: Record; extended?: Record; custom?: Record; }; /** ผลตรวจ ticket ที่ stamp มากับไฟล์ (exp + HmacSha256 ด้วย secret ฝั่ง server) */ verify: Record; } /** * snapshot fields ต่อ version — backend เก็บ 3 รูปแบบ: * - ปัจจุบัน (2026-10-30): ก้อน extract snapshot `{cc, bookmark, properties, verify}` * เหมือน return ของ /api/template/extract (server แกะจากไฟล์เอง) * - เอกสารผูก template: `{ [fieldKey]: { value, missing } }` * - เอกสารไม่ผูก template (track เองจาก add-in): map ดิบ `{ [tag]: text }` * UI ต้อง handle ได้ทั้งหมด (ใช้ readSnapshotField ช่วยอ่าน) */ export type FieldsSnapshot = | ExtractSnapshotFields | Record | Record; /** item ของ GET /api/documents/{documentId}/versions */ export interface VersionRecord { hasPdf?: boolean; versionId: string; versionNumber: number; /** ISO-8601 */ createdAt: string; createdByUserId: string; /** ชื่อผู้สร้าง — ส่วนเสริมของ DTO กลุ่ม docver (mock/demo อาจไม่มี → UI fallback เป็น userId) */ createdByUserName?: string; /** SHA256 hex */ contentHash: string; fields: FieldsSnapshot | null; /** คำอธิบาย version แบบ commit message ที่ผู้ใช้พิมพ์ตอนสร้าง (FR-13) — null ได้ */ message: string | null; } /** อ่านค่า + สถานะ missing ของ field หนึ่งจาก snapshot ไม่ว่าจะเก็บรูปแบบไหน — ไม่มี field นี้คืน null * รูปแบบ extract snapshot (2026-10-30) ค่า CC อยู่ใต้ `cc` — อ่านซ้ำเข้า map ดิบรอบเดียวกัน */ export function readSnapshotField( snapshot: FieldsSnapshot | null, key: string ): FieldSnapshotEntry | null { if (!snapshot) { return null; } // Record ธรรมดาไม่ถูก `in` ตัดออกจาก union (มี index signature ครอบทุก key) — เช็คแล้ว // บอกชนิดตรง ๆ ว่าเป็นก้อน extract snapshot (key "cc" ชนกับ tag ชื่อเดียวกันยอมรับเป็น // edge case ของการเดารูปจากข้อมูลเก่า) if ("cc" in snapshot) { const cc = (snapshot as ExtractSnapshotFields).cc; return readSnapshotField(cc, key); } const raw = snapshot[key]; if (raw === undefined) { return null; } if (typeof raw === "string") { return { value: raw, missing: false }; } return { value: raw.value, missing: raw.missing }; }