import { Default, DefaultNoExclude, IfNever, Replace, JSONValue } from '@zimic/utils/types'; import { HttpMethodSchema, HttpRequestSchema, HttpResponseSchema, HttpStatusCode } from '@/types/schema'; import HttpFormData from '../formData/HttpFormData'; import { HttpFormDataSchema } from '../formData/types'; import HttpHeaders from '../headers/HttpHeaders'; import { HttpHeadersSchema } from '../headers/types'; import HttpSearchParams from '../searchParams/HttpSearchParams'; import { HttpSearchParamsSchema } from '../searchParams/types'; /** The body type for HTTP requests and responses. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any export type HttpBody = JSONValue | HttpFormData | HttpSearchParams | Blob | ArrayBuffer | ReadableStream; export namespace HttpBody { /** A loose version of the HTTP body type. JSON values are not strictly typed. */ export type Loose = Replace; } /** * An HTTP headers object with a strictly-typed schema. Fully compatible with the built-in * {@link https://developer.mozilla.org/docs/Web/API/Headers `Headers`} class. */ export type StrictHeaders = Pick< HttpHeaders, keyof Headers >; /** * An HTTP search params object with a strictly-typed schema. Fully compatible with the built-in * {@link https://developer.mozilla.org/docs/Web/API/URLSearchParams `URLSearchParams`} class. */ export type StrictURLSearchParams = Pick< HttpSearchParams, keyof URLSearchParams >; /** * An HTTP form data object with a strictly-typed schema. Fully compatible with the built-in * {@link https://developer.mozilla.org/docs/Web/API/FormData `FormData`} class. */ export type StrictFormData = Pick< HttpFormData, keyof FormData >; /** * An HTTP request with a strictly-typed JSON body. Fully compatible with the built-in * {@link https://developer.mozilla.org/docs/Web/API/Request `Request`} class. */ export interface HttpRequest< StrictBody extends HttpBody.Loose = HttpBody.Loose, StrictHeadersSchema extends HttpHeadersSchema.Loose = HttpHeadersSchema.Loose, > extends Request { headers: StrictHeaders; text: () => Promise; json: () => Promise< StrictBody extends string | Exclude ? never : Replace >; formData: () => Promise< StrictBody extends HttpFormData ? StrictFormData : StrictBody extends HttpSearchParams ? StrictFormData : StrictBody extends null | undefined ? never : FormData >; clone: () => HttpRequest; } /** * An HTTP response with a strictly-typed JSON body and status code. Fully compatible with the built-in * {@link https://developer.mozilla.org/docs/Web/API/Response `Response`} class. */ export interface HttpResponse< StrictBody extends HttpBody.Loose = HttpBody.Loose, StrictHeadersSchema extends HttpHeadersSchema.Loose = HttpHeadersSchema.Loose, StatusCode extends number = number, > extends Response { ok: StatusCode extends HttpStatusCode.Information | HttpStatusCode.Success | HttpStatusCode.Redirection ? true : false; status: StatusCode; headers: StrictHeaders; text: () => Promise; json: () => Promise< StrictBody extends string | Exclude ? never : Replace >; formData: () => Promise< StrictBody extends HttpFormData ? StrictFormData : StrictBody extends HttpSearchParams ? StrictFormData : StrictBody extends null | undefined ? never : FormData >; clone: () => HttpResponse; } type HttpRequestHeadersSchemaFromBody< RequestSchema extends HttpRequestSchema, DefaultHeadersSchema, > = 'body' extends keyof RequestSchema ? [RequestSchema['body']] extends [never] ? DefaultHeadersSchema : [Extract] extends [never] ? 'headers' extends keyof RequestSchema ? [RequestSchema['headers']] extends [never] ? DefaultHeadersSchema : 'content-type' extends keyof Default ? DefaultHeadersSchema : { 'content-type': 'application/json' } : { 'content-type': 'application/json' } : DefaultHeadersSchema : DefaultHeadersSchema; export type HttpRequestHeadersSchema = 'headers' extends keyof MethodSchema['request'] ? [MethodSchema['request']['headers']] extends [never] ? HttpRequestHeadersSchemaFromBody, never> : | (MethodSchema['request']['headers'] & HttpRequestHeadersSchemaFromBody, {}>) | Extract : HttpRequestHeadersSchemaFromBody, never>; export type HttpRequestSearchParamsSchema = 'searchParams' extends keyof MethodSchema['request'] ? Default['searchParams'] : never; export type HttpRequestBodySchema = Replace< IfNever['body']>, null>, undefined, null >; type HttpResponseHeadersSchemaFromBody< ResponseSchema extends HttpResponseSchema, DefaultHeadersSchema, > = 'body' extends keyof ResponseSchema ? [ResponseSchema['body']] extends [never] ? DefaultHeadersSchema : [Extract] extends [never] ? 'headers' extends keyof ResponseSchema ? [ResponseSchema['headers']] extends [never] ? DefaultHeadersSchema : 'content-type' extends keyof Default ? DefaultHeadersSchema : { 'content-type': 'application/json' } : { 'content-type': 'application/json' } : DefaultHeadersSchema : DefaultHeadersSchema; export type HttpResponseHeadersSchema< MethodSchema extends HttpMethodSchema, StatusCode extends HttpStatusCode, > = 'headers' extends keyof Default[StatusCode] ? [Default[StatusCode]] extends [never] ? HttpResponseHeadersSchemaFromBody[StatusCode]>, never> : | (Default[StatusCode]>['headers'] & HttpResponseHeadersSchemaFromBody[StatusCode]>, {}>) | Extract[StatusCode]>['headers'], undefined> : HttpResponseHeadersSchemaFromBody[StatusCode]>, never>; export type HttpResponseBodySchema = Replace< IfNever[StatusCode]>['body']>, null>, undefined, null >;