import type { z } from 'zod/v4'; import type { InferSchemaInput, InferSchemaOutput } from '../apiContracts.ts'; import type { HttpStatusCode, SuccessfulHttpStatusCode } from '../HttpStatusCodes.ts'; import type { Prettify } from '../typeUtils.ts'; import type { ContractNoBody } from './constants.ts'; import type { ResponsesByStatusCode, SseSchemaByEventName } from './contractResponse.ts'; import type { ApiContract } from './defineApiContract.ts'; import type { ContractResponseMode, SseEventOf } from './inferTypes.ts'; export type HeadersParam = T | (() => T) | (() => Promise); type ExtractRequestBody = T extends { requestBodySchema: z.ZodType; } ? T['requestBodySchema'] : undefined; type StreamingParam = ContractResponseMode extends 'dual' ? { streaming: TIsStreaming; } : { streaming?: never; }; export type DefaultStreaming = ContractResponseMode extends 'sse' ? true : false; type RequiredWhenDefined = [T] extends [undefined] ? { [K in TKey]?: undefined; } : { [K in TKey]: TExtra; }; export type ClientRequestParams = Prettify & RequiredWhenDefined, 'pathParams'> & RequiredWhenDefined>, 'body'> & RequiredWhenDefined, 'queryParams'> & RequiredWhenDefined, 'headers', HeadersParam>> & { pathPrefix?: string; }>; type InferClientResponseHeaders = TApiContract['responseHeaderSchema'] extends z.ZodType ? Omit, keyof InferSchemaOutput> & InferSchemaOutput : Record; /** * Maps a single responsesByStatusCode entry value to its TypeScript body type. */ type InferClientResponseBody = T extends typeof ContractNoBody ? null : T extends z.ZodType ? InferSchemaOutput : T extends { _tag: 'TextResponse'; } ? string : T extends { _tag: 'BlobResponse'; } ? Blob : T extends { _tag: 'SseResponse'; schemaByEventName: infer S extends SseSchemaByEventName; } ? AsyncIterable> : T extends { _tag: 'AnyOfResponses'; responses: Array; } ? InferClientResponseBody : never; /** * Like InferClientResponseBody but returns only SSE bodies — non-SSE entries resolve to never. */ type SseInferClientResponseBody = Extract, AsyncIterable>; /** * Like InferClientResponseBody but returns only non-SSE bodies — SSE entries resolve to never. */ type NonSseInferClientResponseBody = Exclude, AsyncIterable>; /** * Infers a discriminated union of `{ statusCode, headers, body }` for SSE mode: * - success status codes → SSE body only (AsyncIterable) * - error status codes → body as-is (all kinds) * * Headers are typed via `InferClientResponseHeaders`: known headers from `responseHeaderSchema` * are strongly typed; all other headers remain accessible as `string | undefined`. */ export type InferSseClientResponse = { [K in keyof TApiContract['responsesByStatusCode'] & HttpStatusCode]: { statusCode: K; headers: InferClientResponseHeaders; body: K extends SuccessfulHttpStatusCode ? SseInferClientResponseBody> : InferClientResponseBody>; }; }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode]; /** * Infers a discriminated union of `{ statusCode, headers, body }` for non-SSE mode: * - success status codes → non-SSE body only (JSON / text / blob / null) * - error status codes → body as-is (all kinds) * * Headers are typed via `InferClientResponseHeaders`: known headers from `responseHeaderSchema` * are strongly typed; all other headers remain accessible as `string | undefined`. */ export type InferNonSseClientResponse = { [K in keyof TApiContract['responsesByStatusCode'] & HttpStatusCode]: { statusCode: K; headers: InferClientResponseHeaders; body: K extends SuccessfulHttpStatusCode ? NonSseInferClientResponseBody> : InferClientResponseBody>; }; }[keyof TApiContract['responsesByStatusCode'] & HttpStatusCode]; export {};