UNPKG

@lokalise/api-contracts

Version:
88 lines (87 loc) 4.25 kB
import type { z } from 'zod/v4'; import type { SuccessfulHttpStatusCode } from '../HttpStatusCodes.ts'; import type { ValueOf } from '../typeUtils.ts'; import type { BlobResponseHandle, ResponseEntry, ResponsesByStatusCode } from './contractResponse.ts'; type ExtractSuccessResponses<T extends ResponsesByStatusCode> = ValueOf<T, Extract<keyof T, SuccessfulHttpStatusCode | '2xx' | 'default'>>; type FlatContentSuccessResponses<TEntry> = (TEntry extends { content: infer TContent; } ? TContent[keyof TContent] : never) | (TEntry extends { allowNoBody: true; } ? { allowNoBody: true; } : never); type FlatSuccessResponses<T extends ResponsesByStatusCode> = Exclude<ExtractSuccessResponses<T>, ResponseEntry> | FlatContentSuccessResponses<Extract<ExtractSuccessResponses<T>, ResponseEntry>>; type SseSchemaOf<T> = T extends { _tag: 'SseBody'; schemaByEventName: infer S; } ? S : never; /** * Extracts the merged SSE event schema map from a responsesByStatusCode map. * Returns the union of all `schemaByEventName` objects from SSE responses (content-map * `sseBody` descriptors). */ export type InferSseSuccessResponses<T extends ResponsesByStatusCode> = SseSchemaOf<FlatSuccessResponses<T>>; /** * Returns true if any success status code entry is a JSON Zod schema * (a bare schema or a content-map JSON descriptor). */ export type HasAnyJsonSuccessResponse<T extends ResponsesByStatusCode> = Extract<FlatSuccessResponses<T>, z.ZodType> extends never ? false : true; type JsonSchemaOf<T> = T extends z.ZodType ? T : never; /** * Extracts the union of JSON Zod schemas from all success responses. * Blob and SSE responses are excluded. */ export type InferJsonSuccessResponses<T extends ResponsesByStatusCode> = JsonSchemaOf<FlatSuccessResponses<T>>; type NonSseBodyOf<T> = T extends { _tag: 'SseBody'; } ? never : T extends { _tag: 'BlobBody'; } ? BlobResponseHandle : T extends z.ZodType ? z.output<T> : undefined; /** * Infers the TypeScript output type of all non-SSE success responses. * JSON schemas → z.output<T>. A blob entry → BlobResponseHandle. A no-body entry → undefined. * An SSE entry → never (excluded). Content-map entries are unpacked before mapping. */ export type InferNonSseSuccessResponses<T extends ResponsesByStatusCode> = NonSseBodyOf<FlatSuccessResponses<T>>; /** * Discriminated union of SSE events inferred from a schemaByEventName map. * Aligns with the browser MessageEvent shape. */ export type SseEventOf<S> = { [K in keyof S]: K extends string ? { type: K; data: S[K] extends z.ZodType ? z.output<S[K]> : never; lastEventId: string; retry: number | undefined; } : never; }[keyof S]; /** * Returns true if any success status code entry is an SSE response * (a content-map `sseBody` descriptor). */ export type HasAnySseSuccessResponse<T extends ResponsesByStatusCode> = Extract<FlatSuccessResponses<T>, { _tag: 'SseBody'; }> extends never ? false : true; /** * Returns true if any success status code entry has a non-SSE response * (JSON, blob, or no-body). Mirrors HasAnySseSuccessResponse. */ export type HasAnyNonSseSuccessResponse<T extends ResponsesByStatusCode> = Exclude<FlatSuccessResponses<T>, { _tag: 'SseBody'; }> extends never ? false : true; /** * Classifies a contract's response mode into one of three cases: * - 'dual' — SSE + non-SSE success responses; caller chooses via streaming param * - 'sse' — SSE-only success responses; always streams * - 'non-sse' — JSON / blob / no-body; never streams */ export type ContractResponseMode<T extends ResponsesByStatusCode> = HasAnySseSuccessResponse<T> extends true ? HasAnyNonSseSuccessResponse<T> extends true ? 'dual' : 'sse' : 'non-sse'; /** * Union of response mode literals available for a given responsesByStatusCode map. */ export type AvailableResponseModes<T extends ResponsesByStatusCode> = (HasAnyJsonSuccessResponse<T> extends true ? 'json' : never) | (HasAnySseSuccessResponse<T> extends true ? 'sse' : never) | (Extract<FlatSuccessResponses<T>, { _tag: 'BlobBody'; }> extends never ? never : 'blob') | (Extract<FlatSuccessResponses<T>, { allowNoBody: true; }> extends never ? never : 'noContent'); export {};