fork of hey-api/openapi-ts because I need some additional things
1// This file is auto-generated by @hey-api/openapi-ts 2 3import { getAuthToken } from '../core/auth.gen'; 4import type { QuerySerializerOptions } from '../core/bodySerializer.gen'; 5import { jsonBodySerializer } from '../core/bodySerializer.gen'; 6import { 7 serializeArrayParam, 8 serializeObjectParam, 9 serializePrimitiveParam, 10} from '../core/pathSerializer.gen'; 11import { getUrl } from '../core/utils.gen'; 12import type { 13 Client, 14 ClientOptions, 15 Config, 16 RequestOptions, 17} from './types.gen'; 18 19export const createQuerySerializer = <T = unknown>({ 20 parameters = {}, 21 ...args 22}: QuerySerializerOptions = {}) => { 23 const querySerializer = (queryParams: T) => { 24 const search: string[] = []; 25 if (queryParams && typeof queryParams === 'object') { 26 for (const name in queryParams) { 27 const value = queryParams[name]; 28 29 if (value === undefined || value === null) { 30 continue; 31 } 32 33 const options = parameters[name] || args; 34 35 if (Array.isArray(value)) { 36 const serializedArray = serializeArrayParam({ 37 allowReserved: options.allowReserved, 38 explode: true, 39 name, 40 style: 'form', 41 value, 42 ...options.array, 43 }); 44 if (serializedArray) search.push(serializedArray); 45 } else if (typeof value === 'object') { 46 const serializedObject = serializeObjectParam({ 47 allowReserved: options.allowReserved, 48 explode: true, 49 name, 50 style: 'deepObject', 51 value: value as Record<string, unknown>, 52 ...options.object, 53 }); 54 if (serializedObject) search.push(serializedObject); 55 } else { 56 const serializedPrimitive = serializePrimitiveParam({ 57 allowReserved: options.allowReserved, 58 name, 59 value: value as string, 60 }); 61 if (serializedPrimitive) search.push(serializedPrimitive); 62 } 63 } 64 } 65 return search.join('&'); 66 }; 67 return querySerializer; 68}; 69 70/** 71 * Infers parseAs value from provided Content-Type header. 72 */ 73export const getParseAs = ( 74 contentType: string | null, 75): Exclude<Config['parseAs'], 'auto'> => { 76 if (!contentType) { 77 // If no Content-Type header is provided, the best we can do is return the raw response body, 78 // which is effectively the same as the 'stream' option. 79 return 'stream'; 80 } 81 82 const cleanContent = contentType.split(';')[0]?.trim(); 83 84 if (!cleanContent) { 85 return; 86 } 87 88 if ( 89 cleanContent.startsWith('application/json') || 90 cleanContent.endsWith('+json') 91 ) { 92 return 'json'; 93 } 94 95 if (cleanContent === 'multipart/form-data') { 96 return 'formData'; 97 } 98 99 if ( 100 ['application/', 'audio/', 'image/', 'video/'].some((type) => 101 cleanContent.startsWith(type), 102 ) 103 ) { 104 return 'blob'; 105 } 106 107 if (cleanContent.startsWith('text/')) { 108 return 'text'; 109 } 110 111 return; 112}; 113 114const checkForExistence = ( 115 options: Pick<RequestOptions, 'auth' | 'query'> & { 116 headers: Headers; 117 }, 118 name?: string, 119): boolean => { 120 if (!name) { 121 return false; 122 } 123 if ( 124 options.headers.has(name) || 125 options.query?.[name] || 126 options.headers.get('Cookie')?.includes(`${name}=`) 127 ) { 128 return true; 129 } 130 return false; 131}; 132 133export const setAuthParams = async ({ 134 security, 135 ...options 136}: Pick<Required<RequestOptions>, 'security'> & 137 Pick<RequestOptions, 'auth' | 'query'> & { 138 headers: Headers; 139 }) => { 140 for (const auth of security) { 141 if (checkForExistence(options, auth.name)) { 142 continue; 143 } 144 145 const token = await getAuthToken(auth, options.auth); 146 147 if (!token) { 148 continue; 149 } 150 151 const name = auth.name ?? 'Authorization'; 152 153 switch (auth.in) { 154 case 'query': 155 if (!options.query) { 156 options.query = {}; 157 } 158 options.query[name] = token; 159 break; 160 case 'cookie': 161 options.headers.append('Cookie', `${name}=${token}`); 162 break; 163 case 'header': 164 default: 165 options.headers.set(name, token); 166 break; 167 } 168 } 169}; 170 171export const buildUrl: Client['buildUrl'] = (options) => 172 getUrl({ 173 baseUrl: options.baseUrl as string, 174 path: options.path, 175 query: options.query, 176 querySerializer: 177 typeof options.querySerializer === 'function' 178 ? options.querySerializer 179 : createQuerySerializer(options.querySerializer), 180 url: options.url, 181 }); 182 183export const mergeConfigs = (a: Config, b: Config): Config => { 184 const config = { ...a, ...b }; 185 if (config.baseUrl?.endsWith('/')) { 186 config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1); 187 } 188 config.headers = mergeHeaders(a.headers, b.headers); 189 return config; 190}; 191 192const headersEntries = (headers: Headers): Array<[string, string]> => { 193 const entries: Array<[string, string]> = []; 194 headers.forEach((value, key) => { 195 entries.push([key, value]); 196 }); 197 return entries; 198}; 199 200export const mergeHeaders = ( 201 ...headers: Array<Required<Config>['headers'] | undefined> 202): Headers => { 203 const mergedHeaders = new Headers(); 204 for (const header of headers) { 205 if (!header) { 206 continue; 207 } 208 209 const iterator = 210 header instanceof Headers 211 ? headersEntries(header) 212 : Object.entries(header); 213 214 for (const [key, value] of iterator) { 215 if (value === null) { 216 mergedHeaders.delete(key); 217 } else if (Array.isArray(value)) { 218 for (const v of value) { 219 mergedHeaders.append(key, v as string); 220 } 221 } else if (value !== undefined) { 222 // assume object headers are meant to be JSON stringified, i.e. their 223 // content value in OpenAPI specification is 'application/json' 224 mergedHeaders.set( 225 key, 226 typeof value === 'object' ? JSON.stringify(value) : (value as string), 227 ); 228 } 229 } 230 } 231 return mergedHeaders; 232}; 233 234type ErrInterceptor<Err, Res, Req, Options> = ( 235 error: Err, 236 response: Res, 237 request: Req, 238 options: Options, 239) => Err | Promise<Err>; 240 241type ReqInterceptor<Req, Options> = ( 242 request: Req, 243 options: Options, 244) => Req | Promise<Req>; 245 246type ResInterceptor<Res, Req, Options> = ( 247 response: Res, 248 request: Req, 249 options: Options, 250) => Res | Promise<Res>; 251 252class Interceptors<Interceptor> { 253 fns: Array<Interceptor | null> = []; 254 255 clear(): void { 256 this.fns = []; 257 } 258 259 eject(id: number | Interceptor): void { 260 const index = this.getInterceptorIndex(id); 261 if (this.fns[index]) { 262 this.fns[index] = null; 263 } 264 } 265 266 exists(id: number | Interceptor): boolean { 267 const index = this.getInterceptorIndex(id); 268 return Boolean(this.fns[index]); 269 } 270 271 getInterceptorIndex(id: number | Interceptor): number { 272 if (typeof id === 'number') { 273 return this.fns[id] ? id : -1; 274 } 275 return this.fns.indexOf(id); 276 } 277 278 update( 279 id: number | Interceptor, 280 fn: Interceptor, 281 ): number | Interceptor | false { 282 const index = this.getInterceptorIndex(id); 283 if (this.fns[index]) { 284 this.fns[index] = fn; 285 return id; 286 } 287 return false; 288 } 289 290 use(fn: Interceptor): number { 291 this.fns.push(fn); 292 return this.fns.length - 1; 293 } 294} 295 296export interface Middleware<Req, Res, Err, Options> { 297 error: Interceptors<ErrInterceptor<Err, Res, Req, Options>>; 298 request: Interceptors<ReqInterceptor<Req, Options>>; 299 response: Interceptors<ResInterceptor<Res, Req, Options>>; 300} 301 302export const createInterceptors = <Req, Res, Err, Options>(): Middleware< 303 Req, 304 Res, 305 Err, 306 Options 307> => ({ 308 error: new Interceptors<ErrInterceptor<Err, Res, Req, Options>>(), 309 request: new Interceptors<ReqInterceptor<Req, Options>>(), 310 response: new Interceptors<ResInterceptor<Res, Req, Options>>(), 311}); 312 313const defaultQuerySerializer = createQuerySerializer({ 314 allowReserved: false, 315 array: { 316 explode: true, 317 style: 'form', 318 }, 319 object: { 320 explode: true, 321 style: 'deepObject', 322 }, 323}); 324 325const defaultHeaders = { 326 'Content-Type': 'application/json', 327}; 328 329export const createConfig = <T extends ClientOptions = ClientOptions>( 330 override: Config<Omit<ClientOptions, keyof T> & T> = {}, 331): Config<Omit<ClientOptions, keyof T> & T> => ({ 332 ...jsonBodySerializer, 333 headers: defaultHeaders, 334 parseAs: 'auto', 335 querySerializer: defaultQuerySerializer, 336 ...override, 337});