type HttpMethod = "get" | "post" | "put" | "patch" | "delete" | "head" | "options" | "trace"; type JsonContent = { "application/json": unknown; }; type ContentOf = T extends { content: infer C; } ? C : never; type JsonOf = T extends { content: infer C; } ? C extends { "application/json": infer J; } ? J : never : never; interface OperationLike { parameters?: { path?: Record; query?: Record; header?: Record; cookie?: Record; }; requestBody?: { content?: JsonContent; }; responses?: Record; } type PathItemLike = Partial>; type PathsLike = Record; type PickResponse = R extends Record ? R extends { 200: infer R200; } ? JsonOf : R extends { 201: infer R201; } ? JsonOf : R extends { 204: unknown; } ? undefined : R extends { default: infer RDef; } ? JsonOf : unknown : unknown; type ParamsOf = Op extends { parameters: { path: infer P; }; } ? [keyof P] extends [never] ? never : P : never; type QueryOf = Op extends { parameters: { query: infer Q; }; } ? [keyof Q] extends [never] ? never : Q : never; type BodyOf = Op extends { requestBody: { content: infer C; }; } ? C extends JsonContent ? C["application/json"] : ContentOf<{ content: C; }> : never; type ResponseOf = Op extends { responses: infer R; } ? PickResponse : unknown; type EndpointFor = Op extends OperationLike ? (ParamsOf extends never ? Record : { params: ParamsOf; }) & (QueryOf extends never ? Record : { query: QueryOf; }) & (BodyOf extends never ? Record : { body: BodyOf; }) & { response: ResponseOf; } : never; /** * All `(path, verb)` pairs flattened into a union of `{ key, op }` records, * one per operation. Distributing over a union here keeps each entry's * operation type linked to the exact verb instead of collapsing into a union * of all verbs in that path. */ type Flatten = { [P in keyof Paths & string] : { [M in HttpMethod & keyof Paths[P]] : { key: `${Uppercase} ${P}`; op: Paths[P][M]; } }[HttpMethod & keyof Paths[P]] }[keyof Paths & string]; /** * Convert an openapi-typescript-shaped `paths` type into a misina * `EndpointsMap`. Each `PATH × METHOD` pair becomes a key like * `"GET /users/{id}"` mapping to `{ params, query, body, response }`. * * Operations without `parameters.path` / `parameters.query` / `requestBody` * have those keys omitted so callers don't need to pass them. */ export type OpenApiEndpoints = { [E in Flatten as E["key"]] : EndpointFor }; export type { EndpointDef, EndpointsMap } from "../typed.mjs";