summaryrefslogtreecommitdiffhomepage
path: root/packages/sdk/js/src/v2/gen/client
diff options
context:
space:
mode:
authorDax <[email protected]>2025-12-07 19:04:14 -0500
committerGitHub <[email protected]>2025-12-07 19:04:14 -0500
commitea7ec60f51f9fe3c6382f644c328188a43545b7b (patch)
tree5204cbc059fe10b87c54ffd25782ad83710bdcdb /packages/sdk/js/src/v2/gen/client
parent6667856ba5dac3e5dd77c7008cee2d09be894472 (diff)
downloadopencode-ea7ec60f51f9fe3c6382f644c328188a43545b7b.tar.gz
opencode-ea7ec60f51f9fe3c6382f644c328188a43545b7b.zip
v2 SDK (#5216)
Co-authored-by: GitHub Action <[email protected]>
Diffstat (limited to 'packages/sdk/js/src/v2/gen/client')
-rw-r--r--packages/sdk/js/src/v2/gen/client/client.gen.ts278
-rw-r--r--packages/sdk/js/src/v2/gen/client/index.ts25
-rw-r--r--packages/sdk/js/src/v2/gen/client/types.gen.ts202
-rw-r--r--packages/sdk/js/src/v2/gen/client/utils.gen.ts289
4 files changed, 794 insertions, 0 deletions
diff --git a/packages/sdk/js/src/v2/gen/client/client.gen.ts b/packages/sdk/js/src/v2/gen/client/client.gen.ts
new file mode 100644
index 000000000..47f140342
--- /dev/null
+++ b/packages/sdk/js/src/v2/gen/client/client.gen.ts
@@ -0,0 +1,278 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
+import { createSseClient } from "../core/serverSentEvents.gen.js"
+import type { HttpMethod } from "../core/types.gen.js"
+import { getValidRequestBody } from "../core/utils.gen.js"
+import type { Client, Config, RequestOptions, ResolvedRequestOptions } from "./types.gen.js"
+import {
+ buildUrl,
+ createConfig,
+ createInterceptors,
+ getParseAs,
+ mergeConfigs,
+ mergeHeaders,
+ setAuthParams,
+} from "./utils.gen.js"
+
+type ReqInit = Omit<RequestInit, "body" | "headers"> & {
+ body?: any
+ headers: ReturnType<typeof mergeHeaders>
+}
+
+export const createClient = (config: Config = {}): Client => {
+ let _config = mergeConfigs(createConfig(), config)
+
+ const getConfig = (): Config => ({ ..._config })
+
+ const setConfig = (config: Config): Config => {
+ _config = mergeConfigs(_config, config)
+ return getConfig()
+ }
+
+ const interceptors = createInterceptors<Request, Response, unknown, ResolvedRequestOptions>()
+
+ const beforeRequest = async (options: RequestOptions) => {
+ const opts = {
+ ..._config,
+ ...options,
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
+ headers: mergeHeaders(_config.headers, options.headers),
+ serializedBody: undefined,
+ }
+
+ if (opts.security) {
+ await setAuthParams({
+ ...opts,
+ security: opts.security,
+ })
+ }
+
+ if (opts.requestValidator) {
+ await opts.requestValidator(opts)
+ }
+
+ if (opts.body !== undefined && opts.bodySerializer) {
+ opts.serializedBody = opts.bodySerializer(opts.body)
+ }
+
+ // remove Content-Type header if body is empty to avoid sending invalid requests
+ if (opts.body === undefined || opts.serializedBody === "") {
+ opts.headers.delete("Content-Type")
+ }
+
+ const url = buildUrl(opts)
+
+ return { opts, url }
+ }
+
+ const request: Client["request"] = async (options) => {
+ // @ts-expect-error
+ const { opts, url } = await beforeRequest(options)
+ const requestInit: ReqInit = {
+ redirect: "follow",
+ ...opts,
+ body: getValidRequestBody(opts),
+ }
+
+ let request = new Request(url, requestInit)
+
+ for (const fn of interceptors.request.fns) {
+ if (fn) {
+ request = await fn(request, opts)
+ }
+ }
+
+ // fetch must be assigned here, otherwise it would throw the error:
+ // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
+ const _fetch = opts.fetch!
+ let response: Response
+
+ try {
+ response = await _fetch(request)
+ } catch (error) {
+ // Handle fetch exceptions (AbortError, network errors, etc.)
+ let finalError = error
+
+ for (const fn of interceptors.error.fns) {
+ if (fn) {
+ finalError = (await fn(error, undefined as any, request, opts)) as unknown
+ }
+ }
+
+ finalError = finalError || ({} as unknown)
+
+ if (opts.throwOnError) {
+ throw finalError
+ }
+
+ // Return error response
+ return opts.responseStyle === "data"
+ ? undefined
+ : {
+ error: finalError,
+ request,
+ response: undefined as any,
+ }
+ }
+
+ for (const fn of interceptors.response.fns) {
+ if (fn) {
+ response = await fn(response, request, opts)
+ }
+ }
+
+ const result = {
+ request,
+ response,
+ }
+
+ if (response.ok) {
+ const parseAs =
+ (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"
+
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
+ let emptyData: any
+ switch (parseAs) {
+ case "arrayBuffer":
+ case "blob":
+ case "text":
+ emptyData = await response[parseAs]()
+ break
+ case "formData":
+ emptyData = new FormData()
+ break
+ case "stream":
+ emptyData = response.body
+ break
+ case "json":
+ default:
+ emptyData = {}
+ break
+ }
+ return opts.responseStyle === "data"
+ ? emptyData
+ : {
+ data: emptyData,
+ ...result,
+ }
+ }
+
+ let data: any
+ switch (parseAs) {
+ case "arrayBuffer":
+ case "blob":
+ case "formData":
+ case "json":
+ case "text":
+ data = await response[parseAs]()
+ break
+ case "stream":
+ return opts.responseStyle === "data"
+ ? response.body
+ : {
+ data: response.body,
+ ...result,
+ }
+ }
+
+ if (parseAs === "json") {
+ if (opts.responseValidator) {
+ await opts.responseValidator(data)
+ }
+
+ if (opts.responseTransformer) {
+ data = await opts.responseTransformer(data)
+ }
+ }
+
+ return opts.responseStyle === "data"
+ ? data
+ : {
+ data,
+ ...result,
+ }
+ }
+
+ const textError = await response.text()
+ let jsonError: unknown
+
+ try {
+ jsonError = JSON.parse(textError)
+ } catch {
+ // noop
+ }
+
+ const error = jsonError ?? textError
+ let finalError = error
+
+ for (const fn of interceptors.error.fns) {
+ if (fn) {
+ finalError = (await fn(error, response, request, opts)) as string
+ }
+ }
+
+ finalError = finalError || ({} as string)
+
+ if (opts.throwOnError) {
+ throw finalError
+ }
+
+ // TODO: we probably want to return error and improve types
+ return opts.responseStyle === "data"
+ ? undefined
+ : {
+ error: finalError,
+ ...result,
+ }
+ }
+
+ const makeMethodFn = (method: Uppercase<HttpMethod>) => (options: RequestOptions) => request({ ...options, method })
+
+ const makeSseFn = (method: Uppercase<HttpMethod>) => async (options: RequestOptions) => {
+ const { opts, url } = await beforeRequest(options)
+ return createSseClient({
+ ...opts,
+ body: opts.body as BodyInit | null | undefined,
+ headers: opts.headers as unknown as Record<string, string>,
+ method,
+ onRequest: async (url, init) => {
+ let request = new Request(url, init)
+ for (const fn of interceptors.request.fns) {
+ if (fn) {
+ request = await fn(request, opts)
+ }
+ }
+ return request
+ },
+ url,
+ })
+ }
+
+ return {
+ buildUrl,
+ connect: makeMethodFn("CONNECT"),
+ delete: makeMethodFn("DELETE"),
+ get: makeMethodFn("GET"),
+ getConfig,
+ head: makeMethodFn("HEAD"),
+ interceptors,
+ options: makeMethodFn("OPTIONS"),
+ patch: makeMethodFn("PATCH"),
+ post: makeMethodFn("POST"),
+ put: makeMethodFn("PUT"),
+ request,
+ setConfig,
+ sse: {
+ connect: makeSseFn("CONNECT"),
+ delete: makeSseFn("DELETE"),
+ get: makeSseFn("GET"),
+ head: makeSseFn("HEAD"),
+ options: makeSseFn("OPTIONS"),
+ patch: makeSseFn("PATCH"),
+ post: makeSseFn("POST"),
+ put: makeSseFn("PUT"),
+ trace: makeSseFn("TRACE"),
+ },
+ trace: makeMethodFn("TRACE"),
+ } as Client
+}
diff --git a/packages/sdk/js/src/v2/gen/client/index.ts b/packages/sdk/js/src/v2/gen/client/index.ts
new file mode 100644
index 000000000..0af63f330
--- /dev/null
+++ b/packages/sdk/js/src/v2/gen/client/index.ts
@@ -0,0 +1,25 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
+export type { Auth } from "../core/auth.gen.js"
+export type { QuerySerializerOptions } from "../core/bodySerializer.gen.js"
+export {
+ formDataBodySerializer,
+ jsonBodySerializer,
+ urlSearchParamsBodySerializer,
+} from "../core/bodySerializer.gen.js"
+export { buildClientParams } from "../core/params.gen.js"
+export { serializeQueryKeyValue } from "../core/queryKeySerializer.gen.js"
+export { createClient } from "./client.gen.js"
+export type {
+ Client,
+ ClientOptions,
+ Config,
+ CreateClientConfig,
+ Options,
+ RequestOptions,
+ RequestResult,
+ ResolvedRequestOptions,
+ ResponseStyle,
+ TDataShape,
+} from "./types.gen.js"
+export { createConfig, mergeHeaders } from "./utils.gen.js"
diff --git a/packages/sdk/js/src/v2/gen/client/types.gen.ts b/packages/sdk/js/src/v2/gen/client/types.gen.ts
new file mode 100644
index 000000000..e053aa406
--- /dev/null
+++ b/packages/sdk/js/src/v2/gen/client/types.gen.ts
@@ -0,0 +1,202 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
+import type { Auth } from "../core/auth.gen.js"
+import type { ServerSentEventsOptions, ServerSentEventsResult } from "../core/serverSentEvents.gen.js"
+import type { Client as CoreClient, Config as CoreConfig } from "../core/types.gen.js"
+import type { Middleware } from "./utils.gen.js"
+
+export type ResponseStyle = "data" | "fields"
+
+export interface Config<T extends ClientOptions = ClientOptions>
+ extends Omit<RequestInit, "body" | "headers" | "method">,
+ CoreConfig {
+ /**
+ * Base URL for all requests made by this client.
+ */
+ baseUrl?: T["baseUrl"]
+ /**
+ * Fetch API implementation. You can use this option to provide a custom
+ * fetch instance.
+ *
+ * @default globalThis.fetch
+ */
+ fetch?: typeof fetch
+ /**
+ * Please don't use the Fetch client for Next.js applications. The `next`
+ * options won't have any effect.
+ *
+ * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead.
+ */
+ next?: never
+ /**
+ * Return the response data parsed in a specified format. By default, `auto`
+ * will infer the appropriate method from the `Content-Type` response header.
+ * You can override this behavior with any of the {@link Body} methods.
+ * Select `stream` if you don't want to parse response data at all.
+ *
+ * @default 'auto'
+ */
+ parseAs?: "arrayBuffer" | "auto" | "blob" | "formData" | "json" | "stream" | "text"
+ /**
+ * Should we return only data or multiple fields (data, error, response, etc.)?
+ *
+ * @default 'fields'
+ */
+ responseStyle?: ResponseStyle
+ /**
+ * Throw an error instead of returning it in the response?
+ *
+ * @default false
+ */
+ throwOnError?: T["throwOnError"]
+}
+
+export interface RequestOptions<
+ TData = unknown,
+ TResponseStyle extends ResponseStyle = "fields",
+ ThrowOnError extends boolean = boolean,
+ Url extends string = string,
+> extends Config<{
+ responseStyle: TResponseStyle
+ throwOnError: ThrowOnError
+ }>,
+ Pick<
+ ServerSentEventsOptions<TData>,
+ "onSseError" | "onSseEvent" | "sseDefaultRetryDelay" | "sseMaxRetryAttempts" | "sseMaxRetryDelay"
+ > {
+ /**
+ * Any body that you want to add to your request.
+ *
+ * {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
+ */
+ body?: unknown
+ path?: Record<string, unknown>
+ query?: Record<string, unknown>
+ /**
+ * Security mechanism(s) to use for the request.
+ */
+ security?: ReadonlyArray<Auth>
+ url: Url
+}
+
+export interface ResolvedRequestOptions<
+ TResponseStyle extends ResponseStyle = "fields",
+ ThrowOnError extends boolean = boolean,
+ Url extends string = string,
+> extends RequestOptions<unknown, TResponseStyle, ThrowOnError, Url> {
+ serializedBody?: string
+}
+
+export type RequestResult<
+ TData = unknown,
+ TError = unknown,
+ ThrowOnError extends boolean = boolean,
+ TResponseStyle extends ResponseStyle = "fields",
+> = ThrowOnError extends true
+ ? Promise<
+ TResponseStyle extends "data"
+ ? TData extends Record<string, unknown>
+ ? TData[keyof TData]
+ : TData
+ : {
+ data: TData extends Record<string, unknown> ? TData[keyof TData] : TData
+ request: Request
+ response: Response
+ }
+ >
+ : Promise<
+ TResponseStyle extends "data"
+ ? (TData extends Record<string, unknown> ? TData[keyof TData] : TData) | undefined
+ : (
+ | {
+ data: TData extends Record<string, unknown> ? TData[keyof TData] : TData
+ error: undefined
+ }
+ | {
+ data: undefined
+ error: TError extends Record<string, unknown> ? TError[keyof TError] : TError
+ }
+ ) & {
+ request: Request
+ response: Response
+ }
+ >
+
+export interface ClientOptions {
+ baseUrl?: string
+ responseStyle?: ResponseStyle
+ throwOnError?: boolean
+}
+
+type MethodFn = <
+ TData = unknown,
+ TError = unknown,
+ ThrowOnError extends boolean = false,
+ TResponseStyle extends ResponseStyle = "fields",
+>(
+ options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, "method">,
+) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>
+
+type SseFn = <
+ TData = unknown,
+ TError = unknown,
+ ThrowOnError extends boolean = false,
+ TResponseStyle extends ResponseStyle = "fields",
+>(
+ options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, "method">,
+) => Promise<ServerSentEventsResult<TData, TError>>
+
+type RequestFn = <
+ TData = unknown,
+ TError = unknown,
+ ThrowOnError extends boolean = false,
+ TResponseStyle extends ResponseStyle = "fields",
+>(
+ options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, "method"> &
+ Pick<Required<RequestOptions<TData, TResponseStyle, ThrowOnError>>, "method">,
+) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>
+
+type BuildUrlFn = <
+ TData extends {
+ body?: unknown
+ path?: Record<string, unknown>
+ query?: Record<string, unknown>
+ url: string
+ },
+>(
+ options: TData & Options<TData>,
+) => string
+
+export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn, SseFn> & {
+ interceptors: Middleware<Request, Response, unknown, ResolvedRequestOptions>
+}
+
+/**
+ * The `createClientConfig()` function will be called on client initialization
+ * and the returned object will become the client's initial configuration.
+ *
+ * You may want to initialize your client this way instead of calling
+ * `setConfig()`. This is useful for example if you're using Next.js
+ * to ensure your client always has the correct values.
+ */
+export type CreateClientConfig<T extends ClientOptions = ClientOptions> = (
+ override?: Config<ClientOptions & T>,
+) => Config<Required<ClientOptions> & T>
+
+export interface TDataShape {
+ body?: unknown
+ headers?: unknown
+ path?: unknown
+ query?: unknown
+ url: string
+}
+
+type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>
+
+export type Options<
+ TData extends TDataShape = TDataShape,
+ ThrowOnError extends boolean = boolean,
+ TResponse = unknown,
+ TResponseStyle extends ResponseStyle = "fields",
+> = OmitKeys<RequestOptions<TResponse, TResponseStyle, ThrowOnError>, "body" | "path" | "query" | "url"> &
+ ([TData] extends [never] ? unknown : Omit<TData, "url">)
diff --git a/packages/sdk/js/src/v2/gen/client/utils.gen.ts b/packages/sdk/js/src/v2/gen/client/utils.gen.ts
new file mode 100644
index 000000000..3b1dfb787
--- /dev/null
+++ b/packages/sdk/js/src/v2/gen/client/utils.gen.ts
@@ -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,
+})