|
|
@@ -0,0 +1,289 @@
|
|
|
+// This file is auto-generated by @hey-api/openapi-ts
|
|
|
+
|
|
|
+import { getAuthToken } from "../core/auth.gen.js"
|
|
|
+import type { QuerySerializerOptions } from "../core/bodySerializer.gen.js"
|
|
|
+import { jsonBodySerializer } from "../core/bodySerializer.gen.js"
|
|
|
+import { serializeArrayParam, serializeObjectParam, serializePrimitiveParam } from "../core/pathSerializer.gen.js"
|
|
|
+import { getUrl } from "../core/utils.gen.js"
|
|
|
+import type { Client, ClientOptions, Config, RequestOptions } from "./types.gen.js"
|
|
|
+
|
|
|
+export const createQuerySerializer = <T = unknown>({ parameters = {}, ...args }: QuerySerializerOptions = {}) => {
|
|
|
+ const querySerializer = (queryParams: T) => {
|
|
|
+ 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 const setAuthParams = async ({
|
|
|
+ security,
|
|
|
+ ...options
|
|
|
+}: Pick<Required<RequestOptions>, "security"> &
|
|
|
+ Pick<RequestOptions, "auth" | "query"> & {
|
|
|
+ headers: Headers
|
|
|
+ }) => {
|
|
|
+ for (const auth of 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: Res,
|
|
|
+ request: Req,
|
|
|
+ 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,
|
|
|
+})
|