import { describe, expect, it } from "vitest"; import type { components } from "../../../src/features/tech-log/contracts/studio/generated.ts"; import { isStudioGatewayError, StudioGatewayError, } from "../../../src/features/tech-log/application/ports/studio-gateway-error.ts"; import type { StudioGateway, } from "../../../src/features/tech-log/application/ports/studio-gateway.ts"; type Equal = (() => Value extends Left ? 1 : 2) extends (() => Value extends Right ? 1 : 2) ? true : false; type Assert = Condition; type Inline = components["schemas"]["Inline"]; type CaseRenderBlock = components["schemas"]["CaseRenderBlock"]; const inlines: Inline[] = [ { type: "TEXT", text: "plain" }, { type: "EMPHASIS", children: [{ type: "TEXT", text: "emphasis" }] }, { type: "STRONG", children: [{ type: "TEXT", text: "strong" }] }, { type: "INLINE_CODE", code: "findById" }, { type: "LINK", label: "TechLog", href: "https://example.com" }, { type: "STATUS", label: "검증 필요", tone: "warning" }, ]; const blocks: CaseRenderBlock[] = [ { type: "HEADING", id: "problem", level: 2, content: [] }, { type: "PARAGRAPH", content: [] }, { type: "BLOCKQUOTE", content: [] }, { type: "UNORDERED_LIST", items: [] }, { type: "ORDERED_LIST", items: [] }, { type: "CODE_BLOCK", code: "select 1", language: "sql", label: null }, { type: "DATA_TABLE", id: "query-counts", caption: "Query counts", rowHeaderColumn: null, columns: [{ id: "query-counts-column-1", label: "Case", alignment: "LEFT" }], rows: [], }, { type: "CALLOUT", tone: "warning", label: "주의", content: [] }, { type: "EVIDENCE_FIGURE", key: "fetch-plan", alt: "Fetch plan", caption: "Measured fetch plan", zoom: true }, ]; type RequiredStudioGatewayOperation = | "getDashboard" | "listDocuments" | "createDocument" | "getDocument" | "saveDocument" | "validateDocument" | "createPreview" | "getCurrentPreview" | "publishDocument" | "unpublishPublication" | "listPublications" | "getPublicationSnapshot" | "getCatalog"; type StudioGatewayExposesNoMissingOrAdditionalOperations = Assert< Equal >; describe("TechLog Studio contracts", () => { it("preserves every public wire discriminator exactly once", () => { expect(inlines.map((inline) => inline.type)).toEqual([ "TEXT", "EMPHASIS", "STRONG", "INLINE_CODE", "LINK", "STATUS", ]); expect(blocks.map((block) => block.type)).toEqual([ "HEADING", "PARAGRAPH", "BLOCKQUOTE", "UNORDERED_LIST", "ORDERED_LIST", "CODE_BLOCK", "DATA_TABLE", "CALLOUT", "EVIDENCE_FIGURE", ]); expect(new Set(blocks.map((block) => block.type)).size).toBe(blocks.length); }); it("keeps RFC 9457-style gateway failures inspectable at the application boundary", () => { const error = new StudioGatewayError({ type: "https://techlog.dev/problems/conflict", title: "Conflict", status: 409, detail: "The working copy has changed.", code: "VERSION_CONFLICT", retryable: false, }); expect(error).toMatchObject({ name: "StudioGatewayError", status: 409, code: "VERSION_CONFLICT", retryable: false, }); expect(isStudioGatewayError(error)).toBe(true); expect(isStudioGatewayError(new DOMException("Aborted", "AbortError"))).toBe(false); }); });