import { describe, expect, it, vi } from "vitest"; import { createFeatureHttpBinding, defineFeatureHttpOperation, type HttpExecutionOutcome, type InstalledHttpOperationExecutor, } from "../../../src/adapters/http/index.ts"; import { mappingFailure, mappingSuccess, } from "../../../src/contracts/boundary-mapper.ts"; import type { InstalledHttpContract, RuntimeValidator, } from "../../../src/contracts/external-contract-runtime.ts"; type ResourceInput = Readonly<{ resourceId: string }>; type ResourceWire = Readonly<{ id: string; title: string }>; type ResourceProblem = Readonly<{ code?: string }>; type Resource = Readonly<{ id: string; title: string }>; function validator(schemaId: string): RuntimeValidator { return Object.freeze({ schemaId, safeParse(value: unknown) { return Object.freeze({ success: true as const, data: value as T, }); }, }); } const LOAD_RESOURCE_CONTRACT = Object.freeze({ contract: Object.freeze({ operationId: "LOAD_RESOURCE", method: "GET" as const, pathTemplate: "/resources/{resourceId}", inputValidator: validator("ResourceInput"), outputValidator: validator("ResourceWire"), problemValidator: validator("ResourceProblem"), acceptedStatuses: Object.freeze([200]), emptyBodyStatuses: Object.freeze([]), retrySemantics: "SAFE" as const, requestBody: "NONE" as const, responseBody: "REQUIRED_JSON" as const, commandRecovery: null, commandEffect: null, projectRequest(input: ResourceInput) { return Object.freeze({ pathValues: Object.freeze({ resourceId: input.resourceId }), queryEntries: Object.freeze([]), body: null, }); }, }), frontend: Object.freeze({ policyId: "TEST_LOAD_RESOURCE", requestByteLimit: 0, responseByteLimit: 8_192, totalDeadlineMs: 1_000, retryBudget: 0 as const, authProfileId: "TEST", diagnosticsOperation: "test.load-resource", }), }) satisfies InstalledHttpContract; const OPERATIONS = Object.freeze({ LOAD_RESOURCE: defineFeatureHttpOperation({ contract: LOAD_RESOURCE_CONTRACT, routeId: "RESOURCE_DETAIL", mapSuccess(value) { if (value.title.length === 0) { return mappingFailure("MAPPING_INVARIANT_REJECTED"); } return mappingSuccess( Object.freeze({ id: value.id, title: value.title }), ); }, mapProblem(problem, metadata) { if (metadata.status !== 409) return undefined; return Object.freeze({ kind: "CONFLICT" as const, code: problem.code ?? "RESOURCE_CONFLICT", }); }, }), } as const); function scriptedExecutor( outcome: HttpExecutionOutcome, ) { const calls: Array< Readonly<{ contract: unknown; input: unknown; context: unknown; }> > = []; const implementation = async ( contract: unknown, input: unknown, context: unknown, ) => { calls.push(Object.freeze({ contract, input, context })); return outcome; }; const execute = vi.fn(implementation) as unknown as InstalledHttpOperationExecutor["execute"]; return { executor: Object.freeze({ execute }) satisfies InstalledHttpOperationExecutor, calls, execute, }; } describe("feature HTTP binding", () => { it("keeps contract-derived input while platform owns route/context execution", async () => { const scripted = scriptedExecutor( Object.freeze({ kind: "SUCCESS" as const, value: Object.freeze({ id: "resource-1", title: "Reference" }), metadata: Object.freeze({ status: 200 }), effect: "NOT_APPLICABLE" as const, }), ); const binding = createFeatureHttpBinding(scripted.executor, OPERATIONS); const result = await binding.execute("LOAD_RESOURCE", { resourceId: "resource-1", }); expect(result).toEqual({ ok: true, value: { id: "resource-1", title: "Reference" }, }); expect(scripted.calls).toEqual([ { contract: LOAD_RESOURCE_CONTRACT, input: { resourceId: "resource-1" }, context: { routeId: "RESOURCE_DETAIL" }, }, ]); }); it("normalizes transport failure before it crosses the feature gateway", async () => { const scripted = scriptedExecutor( Object.freeze({ kind: "TRANSPORT_FAILURE" as const, failure: Object.freeze({ kind: "TIMEOUT" as const, retryable: true, }), effect: "NOT_STARTED" as const, }), ); const binding = createFeatureHttpBinding(scripted.executor, OPERATIONS); const result = await binding.execute("LOAD_RESOURCE", { resourceId: "resource-1", }); expect(result.ok).toBe(false); if (result.ok) return; expect(result.error.kind).toBe("REQUEST_TIMEOUT"); expect(result.error.operationId).toBe("LOAD_RESOURCE"); expect(result.error.effect).toBe("NOT_STARTED"); }); it("turns a domain mapper rejection into the shared mapping failure", async () => { const scripted = scriptedExecutor( Object.freeze({ kind: "SUCCESS" as const, value: Object.freeze({ id: "resource-1", title: "" }), metadata: Object.freeze({ status: 200 }), effect: "NOT_APPLICABLE" as const, }), ); const binding = createFeatureHttpBinding(scripted.executor, OPERATIONS); const result = await binding.execute("LOAD_RESOURCE", { resourceId: "resource-1", }); expect(result.ok).toBe(false); if (result.ok) return; expect(result.error.kind).toBe("MAPPING_CONTRACT_VIOLATION"); expect(result.error.code).toBe("MAPPING_INVARIANT_REJECTED"); }); it("lets the feature interpret a typed business problem", async () => { const scripted = scriptedExecutor( Object.freeze({ kind: "PROBLEM" as const, problem: Object.freeze({ code: "RESOURCE_NAME_EXISTS" }), metadata: Object.freeze({ status: 409 }), effect: "NOT_APPLIED" as const, }), ); const binding = createFeatureHttpBinding(scripted.executor, OPERATIONS); const result = await binding.execute("LOAD_RESOURCE", { resourceId: "resource-1", }); expect(result).toMatchObject({ ok: false, error: { kind: "CONFLICT", code: "RESOURCE_NAME_EXISTS", httpStatus: 409, }, }); }); });