UNPKG

@sizium/api-client

Version:

REST API client for Sizium. Get the actual size of any local or remote package

418 lines (374 loc) 15 kB
// HTTP types type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace"; /** 2XX statuses */ type OkStatus = 200 | 201 | 202 | 203 | 204 | 206 | 207 | "2XX"; /** 4XX and 5XX statuses */ // biome-ignore format: keep on one line type ErrorStatus = 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 | '5XX' | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 444 | 450 | 451 | 497 | 498 | 499 | '4XX' | "default"; // OpenAPI type helpers /** Given an OpenAPI **Paths Object**, find all paths that have the given method */ type PathsWithMethod<Paths extends {}, PathnameMethod extends HttpMethod> = { [Pathname in keyof Paths]: Paths[Pathname] extends { [K in PathnameMethod]: any; } ? Pathname : never; }[keyof Paths]; /** Return `responses` for an Operation Object */ type ResponseObjectMap<T> = T extends { responses: any } ? T["responses"] : unknown; /** Return `content` for a Response Object */ type ResponseContent<T> = T extends { content: any } ? T["content"] : unknown; /** Return type of `requestBody` for an Operation Object */ type OperationRequestBody<T> = "requestBody" extends keyof T ? T["requestBody"] : never; /** Internal helper to get object type with only the `requestBody` property */ type PickRequestBody<T> = "requestBody" extends keyof T ? Pick<T, "requestBody"> : never; /** Resolve to `true` if request body is optional, else `false` */ type IsOperationRequestBodyOptional<T> = RequiredKeysOf<PickRequestBody<T>> extends never ? true : false; /** Internal helper used in OperationRequestBodyContent */ type OperationRequestBodyMediaContent<T> = IsOperationRequestBodyOptional<T> extends true ? ResponseContent<NonNullable<OperationRequestBody<T>>> | undefined : ResponseContent<OperationRequestBody<T>>; /** Return first `content` from a Request Object Mapping, allowing any media type */ type OperationRequestBodyContent<T> = FilterKeys<OperationRequestBodyMediaContent<T>, MediaType> extends never ? FilterKeys<NonNullable<OperationRequestBodyMediaContent<T>>, MediaType> | undefined : FilterKeys<OperationRequestBodyMediaContent<T>, MediaType>; /** Return all 2XX responses from a Response Object Map */ type SuccessResponse< T extends Record<string | number, any>, Media extends MediaType = MediaType, > = GetResponseContent<T, Media, OkStatus>; type GetResponseContent< T extends Record<string | number, any>, Media extends MediaType = MediaType, ResponseCode extends keyof T = keyof T, > = ResponseCode extends keyof T ? { [K in ResponseCode]: T[K]["content"] extends Record<string, any> ? FilterKeys<T[K]["content"], Media> extends never ? T[K]["content"] : FilterKeys<T[K]["content"], Media> : K extends keyof T ? T[K]["content"] : never; }[ResponseCode] : never; /** * Return all 5XX and 4XX responses (in that order) from a Response Object Map */ type ErrorResponse< T extends Record<string | number, any>, Media extends MediaType = MediaType, > = GetResponseContent<T, Media, ErrorStatus>; // Generic TS utils /** Find first match of multiple keys */ type FilterKeys<Obj, Matchers> = Obj[keyof Obj & Matchers]; /** Return any `[string]/[string]` media type (important because openapi-fetch allows any content response, not just JSON-like) */ type MediaType = `${string}/${string}`; /** Helper to get the required keys of an object. If no keys are required, will be `undefined` with strictNullChecks enabled, else `never` */ type RequiredKeysOfHelper<T> = { // biome-ignore lint/complexity/noBannedTypes: `{}` is necessary here [K in keyof T]: {} extends Pick<T, K> ? never : K; }[keyof T]; /** Get the required keys of an object, or `never` if no keys are required */ type RequiredKeysOf<T> = RequiredKeysOfHelper<T> extends undefined ? never : RequiredKeysOfHelper<T>; /** Options for each client instance */ interface ClientOptions extends Omit<RequestInit, "headers"> { /** set the common root URL for all API requests */ baseUrl?: string; /** custom fetch (defaults to globalThis.fetch) */ fetch?: (input: Request) => Promise<Response>; /** custom Request (defaults to globalThis.Request) */ Request?: typeof Request; /** global querySerializer */ querySerializer?: QuerySerializer<unknown> | QuerySerializerOptions; /** global bodySerializer */ bodySerializer?: BodySerializer<unknown>; headers?: HeadersOptions; /** RequestInit extension object to pass as 2nd argument to fetch when supported (defaults to undefined) */ requestInitExt?: Record<string, unknown>; } type HeadersOptions = | Required<RequestInit>["headers"] | Record<string, string | number | boolean | (string | number | boolean)[] | null | undefined>; type QuerySerializer<T> = ( query: T extends { parameters: any } ? NonNullable<T["parameters"]["query"]> : Record<string, unknown>, ) => string; /** @see https://swagger.io/docs/specification/serialization/#query */ type QuerySerializerOptions = { /** Set serialization for arrays. @see https://swagger.io/docs/specification/serialization/#query */ array?: { /** default: "form" */ style: "form" | "spaceDelimited" | "pipeDelimited"; /** default: true */ explode: boolean; }; /** Set serialization for objects. @see https://swagger.io/docs/specification/serialization/#query */ object?: { /** default: "deepObject" */ style: "form" | "deepObject"; /** default: true */ explode: boolean; }; /** * The `allowReserved` keyword specifies whether the reserved characters * `:/?#[]@!$&'()*+,;=` in parameter values are allowed to be sent as they * are, or should be percent-encoded. By default, allowReserved is `false`, * and reserved characters are percent-encoded. * @see https://swagger.io/docs/specification/serialization/#query */ allowReserved?: boolean; }; type BodySerializer<T> = (body: OperationRequestBodyContent<T>) => any; type BodyType<T = unknown> = { json: T; text: Awaited<ReturnType<Response["text"]>>; blob: Awaited<ReturnType<Response["blob"]>>; arrayBuffer: Awaited<ReturnType<Response["arrayBuffer"]>>; stream: Response["body"]; }; type ParseAs = keyof BodyType; type ParseAsResponse<T, Options> = Options extends { parseAs: ParseAs; } ? BodyType<T>[Options["parseAs"]] : T; interface DefaultParamsOption { params?: { query?: Record<string, unknown>; }; } type ParamsOption<T> = T extends { parameters: any; } ? RequiredKeysOf<T["parameters"]> extends never ? { params?: T["parameters"] } : { params: T["parameters"] } : DefaultParamsOption; type RequestBodyOption<T> = OperationRequestBodyContent<T> extends never ? { body?: never } : IsOperationRequestBodyOptional<T> extends true ? { body?: OperationRequestBodyContent<T> } : { body: OperationRequestBodyContent<T> }; type FetchOptions<T> = RequestOptions<T> & Omit<RequestInit, "body" | "headers">; type FetchResponse<T extends Record<string | number, any>, Options, Media extends MediaType> = | { data: ParseAsResponse<SuccessResponse<ResponseObjectMap<T>, Media>, Options>; error?: never; response: Response; } | { data?: never; error: ErrorResponse<ResponseObjectMap<T>, Media>; response: Response; }; type RequestOptions<T> = ParamsOption<T> & RequestBodyOption<T> & { baseUrl?: string; querySerializer?: QuerySerializer<T> | QuerySerializerOptions; bodySerializer?: BodySerializer<T>; parseAs?: ParseAs; fetch?: ClientOptions["fetch"]; headers?: HeadersOptions; }; type MergedOptions<T = unknown> = { baseUrl: string; parseAs: ParseAs; querySerializer: QuerySerializer<T>; bodySerializer: BodySerializer<T>; fetch: typeof globalThis.fetch; }; interface MiddlewareCallbackParams { /** Current Request object */ request: Request; /** The original OpenAPI schema path (including curly braces) */ readonly schemaPath: string; /** OpenAPI parameters as provided from openapi-fetch */ readonly params: { query?: Record<string, unknown>; header?: Record<string, unknown>; path?: Record<string, unknown>; cookie?: Record<string, unknown>; }; /** Unique ID for this request */ readonly id: string; /** createClient options (read-only) */ readonly options: MergedOptions; } type MiddlewareOnRequest = ( options: MiddlewareCallbackParams, ) => void | Request | Response | undefined | Promise<Request | Response | undefined | void>; type MiddlewareOnResponse = ( options: MiddlewareCallbackParams & { response: Response }, ) => void | Response | undefined | Promise<Response | undefined | void>; type MiddlewareOnError = ( options: MiddlewareCallbackParams & { error: unknown }, ) => void | Response | Error | Promise<void | Response | Error>; type Middleware = | { onRequest: MiddlewareOnRequest; onResponse?: MiddlewareOnResponse; onError?: MiddlewareOnError; } | { onRequest?: MiddlewareOnRequest; onResponse: MiddlewareOnResponse; onError?: MiddlewareOnError; } | { onRequest?: MiddlewareOnRequest; onResponse?: MiddlewareOnResponse; onError: MiddlewareOnError; }; /** This type helper makes the 2nd function param required if params/requestBody are required; otherwise, optional */ type MaybeOptionalInit<Params, Location extends keyof Params> = RequiredKeysOf< FetchOptions<FilterKeys<Params, Location>> > extends never ? FetchOptions<FilterKeys<Params, Location>> | undefined : FetchOptions<FilterKeys<Params, Location>>; // The final init param to accept. // - Determines if the param is optional or not. // - Performs arbitrary [key: string] addition. // Note: the addition MUST happen after all the inference happens (otherwise TS can’t infer if init is required or not). type InitParam<Init> = RequiredKeysOf<Init> extends never ? [(Init & { [key: string]: unknown })?] : [Init & { [key: string]: unknown }]; type ClientMethod< Paths extends Record<string, Record<HttpMethod, {}>>, Method extends HttpMethod, Media extends MediaType, > = <Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>>( url: Path, ...init: InitParam<Init> ) => Promise<FetchResponse<Paths[Path][Method], Init, Media>>; type ClientRequestMethod<Paths extends Record<string, Record<HttpMethod, {}>>, Media extends MediaType> = < Method extends HttpMethod, Path extends PathsWithMethod<Paths, Method>, Init extends MaybeOptionalInit<Paths[Path], Method>, >( method: Method, url: Path, ...init: InitParam<Init> ) => Promise<FetchResponse<Paths[Path][Method], Init, Media>>; interface Client<Paths extends {}, Media extends MediaType = MediaType> { request: ClientRequestMethod<Paths, Media>; /** Call a GET endpoint */ GET: ClientMethod<Paths, "get", Media>; /** Call a PUT endpoint */ PUT: ClientMethod<Paths, "put", Media>; /** Call a POST endpoint */ POST: ClientMethod<Paths, "post", Media>; /** Call a DELETE endpoint */ DELETE: ClientMethod<Paths, "delete", Media>; /** Call a OPTIONS endpoint */ OPTIONS: ClientMethod<Paths, "options", Media>; /** Call a HEAD endpoint */ HEAD: ClientMethod<Paths, "head", Media>; /** Call a PATCH endpoint */ PATCH: ClientMethod<Paths, "patch", Media>; /** Call a TRACE endpoint */ TRACE: ClientMethod<Paths, "trace", Media>; /** Register middleware */ use(...middleware: Middleware[]): void; /** Unregister middleware */ eject(...middleware: Middleware[]): void; } declare function createClient$2<Paths extends {}, Media extends MediaType = MediaType>( clientOptions?: ClientOptions, ): Client<Paths, Media>; /** * Creates an instance of the OpenAPI client. * @returns {ReturnType<typeof OpenApiCreateClient>} - The configured OpenAPI client. * @example * import type { paths } from "./openapi.d.ts" // Types generated by `buildSchema` function from `@backan/builder` * * // create client * const client = createClient<paths>( { * baseUrl : 'http://localhost:1312/', * } ) * * // example of call * const response = await client.GET( '/random/child', { * params : { query : { value : 'myValue', }, }, * } ) * * console.log( response ) */ declare const createClient$1: typeof createClient$2; interface paths { "/size": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Get Package size data */ get: { parameters: { query: { /** @description Set the input */ input: string; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Successfully fetched data */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": Record<string, never>; }; }; /** @description Bad request */ 400: { headers: { [name: string]: unknown; }; content: { "application/json": { /** @enum {number} */ status: 400; id: string; message: string; error: Record<string, never>; help: string; }; }; }; /** @description Internal Server error */ 500: { headers: { [name: string]: unknown; }; content: { "application/json": { /** @enum {number} */ status: 500; id: string; message: string; error: Record<string, never>; help: string; }; }; }; }; }; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; } type ClientOpts = NonNullable<Parameters<typeof createClient$1>[0]>; type ClientRes = ReturnType<typeof createClient$1<paths>>; declare const createClient: (opts?: ClientOpts) => ClientRes; export { createClient }; export type { ClientOpts, ClientRes, paths };