| // This file is auto-generated by @hey-api/openapi-ts |
| |
| import { getAuthToken } from '../core/auth.gen'; |
| import type { QuerySerializerOptions } from '../core/bodySerializer.gen'; |
| import { jsonBodySerializer } from '../core/bodySerializer.gen'; |
| import { |
| serializeArrayParam, |
| serializeObjectParam, |
| serializePrimitiveParam, |
| } from '../core/pathSerializer.gen'; |
| import { getUrl } from '../core/utils.gen'; |
| import type { Client, ClientOptions, Config, RequestOptions } from './types.gen'; |
| |
| export const createQuerySerializer = <T = unknown>({ |
| parameters = {}, |
| ...args |
| }: QuerySerializerOptions = {}): ((queryParams: T) => string) => { |
| const querySerializer = (queryParams: T): string => { |
| const search: string[] = []; |
| if (queryParams && typeof queryParams === 'object') { |
| for (const name in queryParams) { |
| const value = queryParams[name]; |
| |
| if (value === undefined || value === null) { |
| continue; |
| } |
| |
| const options = parameters[name] || args; |
| |
| if (Array.isArray(value)) { |
| const serializedArray = serializeArrayParam({ |
| allowReserved: options.allowReserved, |
| explode: true, |
| name, |
| style: 'form', |
| value, |
| ...options.array, |
| }); |
| if (serializedArray) search.push(serializedArray); |
| } else if (typeof value === 'object') { |
| const serializedObject = serializeObjectParam({ |
| allowReserved: options.allowReserved, |
| explode: true, |
| name, |
| style: 'deepObject', |
| value: value as Record<string, unknown>, |
| ...options.object, |
| }); |
| if (serializedObject) search.push(serializedObject); |
| } else { |
| const serializedPrimitive = serializePrimitiveParam({ |
| allowReserved: options.allowReserved, |
| name, |
| value: value as string, |
| }); |
| if (serializedPrimitive) search.push(serializedPrimitive); |
| } |
| } |
| } |
| return search.join('&'); |
| }; |
| return querySerializer; |
| }; |
| |
| /** |
| * Infers parseAs value from provided Content-Type header. |
| */ |
| export const getParseAs = (contentType: string | null): Exclude<Config['parseAs'], 'auto'> => { |
| if (!contentType) { |
| // If no Content-Type header is provided, the best we can do is return the raw response body, |
| // which is effectively the same as the 'stream' option. |
| return 'stream'; |
| } |
| |
| const cleanContent = contentType.split(';')[0]?.trim(); |
| |
| if (!cleanContent) { |
| return; |
| } |
| |
| if (cleanContent.startsWith('application/json') || cleanContent.endsWith('+json')) { |
| return 'json'; |
| } |
| |
| if (cleanContent === 'multipart/form-data') { |
| return 'formData'; |
| } |
| |
| if ( |
| ['application/', 'audio/', 'image/', 'video/'].some((type) => cleanContent.startsWith(type)) |
| ) { |
| return 'blob'; |
| } |
| |
| if (cleanContent.startsWith('text/')) { |
| return 'text'; |
| } |
| |
| return; |
| }; |
| |
| const checkForExistence = ( |
| options: Pick<RequestOptions, 'auth' | 'query'> & { |
| headers: Headers; |
| }, |
| name?: string, |
| ): boolean => { |
| if (!name) { |
| return false; |
| } |
| if ( |
| options.headers.has(name) || |
| options.query?.[name] || |
| options.headers.get('Cookie')?.includes(`${name}=`) |
| ) { |
| return true; |
| } |
| return false; |
| }; |
| |
| export async function setAuthParams( |
| options: Pick<RequestOptions, 'auth' | 'query' | 'security'> & { |
| headers: Headers; |
| }, |
| ): Promise<void> { |
| for (const auth of options.security ?? []) { |
| if (checkForExistence(options, auth.name)) { |
| continue; |
| } |
| |
| const token = await getAuthToken(auth, options.auth); |
| |
| if (!token) { |
| continue; |
| } |
| |
| const name = auth.name ?? 'Authorization'; |
| |
| switch (auth.in) { |
| case 'query': |
| if (!options.query) { |
| options.query = {}; |
| } |
| options.query[name] = token; |
| break; |
| case 'cookie': |
| options.headers.append('Cookie', `${name}=${token}`); |
| break; |
| case 'header': |
| default: |
| options.headers.set(name, token); |
| break; |
| } |
| } |
| } |
| |
| export const buildUrl: Client['buildUrl'] = (options) => |
| getUrl({ |
| baseUrl: options.baseUrl as string, |
| path: options.path, |
| query: options.query, |
| querySerializer: |
| typeof options.querySerializer === 'function' |
| ? options.querySerializer |
| : createQuerySerializer(options.querySerializer), |
| url: options.url, |
| }); |
| |
| export const mergeConfigs = (a: Config, b: Config): Config => { |
| const config = { ...a, ...b }; |
| if (config.baseUrl?.endsWith('/')) { |
| config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); |
| } |
| config.headers = mergeHeaders(a.headers, b.headers); |
| return config; |
| }; |
| |
| const headersEntries = (headers: Headers): Array<[string, string]> => { |
| const entries: Array<[string, string]> = []; |
| headers.forEach((value, key) => { |
| entries.push([key, value]); |
| }); |
| return entries; |
| }; |
| |
| export const mergeHeaders = ( |
| ...headers: Array<Required<Config>['headers'] | undefined> |
| ): Headers => { |
| const mergedHeaders = new Headers(); |
| for (const header of headers) { |
| if (!header) { |
| continue; |
| } |
| |
| const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header); |
| |
| for (const [key, value] of iterator) { |
| if (value === null) { |
| mergedHeaders.delete(key); |
| } else if (Array.isArray(value)) { |
| for (const v of value) { |
| mergedHeaders.append(key, v as string); |
| } |
| } else if (value !== undefined) { |
| // assume object headers are meant to be JSON stringified, i.e., their |
| // content value in OpenAPI specification is 'application/json' |
| mergedHeaders.set( |
| key, |
| typeof value === 'object' ? JSON.stringify(value) : (value as string), |
| ); |
| } |
| } |
| } |
| return mergedHeaders; |
| }; |
| |
| type ErrInterceptor<Err, Res, Req, Options> = ( |
| error: Err, |
| /** response may be undefined due to a network error where no response object is produced */ |
| response: Res | undefined, |
| /** request may be undefined, because error may be from building the request object itself */ |
| request: Req | undefined, |
| options: Options, |
| ) => Err | Promise<Err>; |
| |
| type ReqInterceptor<Req, Options> = (request: Req, options: Options) => Req | Promise<Req>; |
| |
| type ResInterceptor<Res, Req, Options> = ( |
| response: Res, |
| request: Req, |
| options: Options, |
| ) => Res | Promise<Res>; |
| |
| class Interceptors<Interceptor> { |
| fns: Array<Interceptor | null> = []; |
| |
| clear(): void { |
| this.fns = []; |
| } |
| |
| eject(id: number | Interceptor): void { |
| const index = this.getInterceptorIndex(id); |
| if (this.fns[index]) { |
| this.fns[index] = null; |
| } |
| } |
| |
| exists(id: number | Interceptor): boolean { |
| const index = this.getInterceptorIndex(id); |
| return Boolean(this.fns[index]); |
| } |
| |
| getInterceptorIndex(id: number | Interceptor): number { |
| if (typeof id === 'number') { |
| return this.fns[id] ? id : -1; |
| } |
| return this.fns.indexOf(id); |
| } |
| |
| update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false { |
| const index = this.getInterceptorIndex(id); |
| if (this.fns[index]) { |
| this.fns[index] = fn; |
| return id; |
| } |
| return false; |
| } |
| |
| use(fn: Interceptor): number { |
| this.fns.push(fn); |
| return this.fns.length - 1; |
| } |
| } |
| |
| export interface Middleware<Req, Res, Err, Options> { |
| error: Interceptors<ErrInterceptor<Err, Res, Req, Options>>; |
| request: Interceptors<ReqInterceptor<Req, Options>>; |
| response: Interceptors<ResInterceptor<Res, Req, Options>>; |
| } |
| |
| export const createInterceptors = <Req, Res, Err, Options>(): Middleware< |
| Req, |
| Res, |
| Err, |
| Options |
| > => ({ |
| error: new Interceptors<ErrInterceptor<Err, Res, Req, Options>>(), |
| request: new Interceptors<ReqInterceptor<Req, Options>>(), |
| response: new Interceptors<ResInterceptor<Res, Req, Options>>(), |
| }); |
| |
| const defaultQuerySerializer = createQuerySerializer({ |
| allowReserved: false, |
| array: { |
| explode: true, |
| style: 'form', |
| }, |
| object: { |
| explode: true, |
| style: 'deepObject', |
| }, |
| }); |
| |
| const defaultHeaders = { |
| 'Content-Type': 'application/json', |
| }; |
| |
| export const createConfig = <T extends ClientOptions = ClientOptions>( |
| override: Config<Omit<ClientOptions, keyof T> & T> = {}, |
| ): Config<Omit<ClientOptions, keyof T> & T> => ({ |
| ...jsonBodySerializer, |
| headers: defaultHeaders, |
| parseAs: 'auto', |
| querySerializer: defaultQuerySerializer, |
| ...override, |
| }); |