Integrate api with hey-api
This commit is contained in:
218
app/openapi/generated/client/client.gen.ts
Normal file
218
app/openapi/generated/client/client.gen.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import { useAsyncData, useFetch, useLazyAsyncData, useLazyFetch } from 'nuxt/app';
|
||||
import { reactive, ref, toValue, watch } from 'vue';
|
||||
|
||||
import { createSseClient } from '../core/serverSentEvents.gen';
|
||||
import type { HttpMethod } from '../core/types.gen';
|
||||
import { getValidRequestBody } from '../core/utils.gen';
|
||||
import type { Client, Config, RequestOptions } from './types.gen';
|
||||
import {
|
||||
buildUrl,
|
||||
createConfig,
|
||||
executeFetchFn,
|
||||
mergeConfigs,
|
||||
mergeHeaders,
|
||||
mergeInterceptors,
|
||||
serializeBody,
|
||||
setAuthParams,
|
||||
unwrapRefs,
|
||||
} from './utils.gen';
|
||||
|
||||
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 beforeRequest = async (options: RequestOptions) => {
|
||||
const opts = {
|
||||
..._config,
|
||||
...options,
|
||||
$fetch: options.$fetch ?? _config.$fetch ?? $fetch,
|
||||
headers: mergeHeaders(_config.headers, options.headers),
|
||||
onRequest: mergeInterceptors(_config.onRequest, options.onRequest),
|
||||
onResponse: mergeInterceptors(_config.onResponse, options.onResponse),
|
||||
};
|
||||
|
||||
if (opts.security) {
|
||||
await setAuthParams({
|
||||
...opts,
|
||||
security: opts.security,
|
||||
});
|
||||
}
|
||||
|
||||
if (opts.requestValidator) {
|
||||
await opts.requestValidator(opts);
|
||||
}
|
||||
|
||||
const url = buildUrl(opts);
|
||||
|
||||
return { opts, url };
|
||||
};
|
||||
|
||||
const request: Client['request'] = ({ asyncDataOptions, composable = '$fetch', ...options }) => {
|
||||
const key = options.key;
|
||||
const opts = {
|
||||
..._config,
|
||||
...options,
|
||||
$fetch: options.$fetch ?? _config.$fetch ?? $fetch,
|
||||
headers: mergeHeaders(_config.headers, options.headers),
|
||||
onRequest: mergeInterceptors(_config.onRequest, options.onRequest),
|
||||
onResponse: mergeInterceptors(_config.onResponse, options.onResponse),
|
||||
};
|
||||
|
||||
const { requestValidator, responseTransformer, responseValidator, security } = opts;
|
||||
if (requestValidator || security) {
|
||||
// auth must happen in interceptors otherwise we'd need to require
|
||||
// asyncContext enabled
|
||||
// https://nuxt.com/docs/guide/going-further/experimental-features#asynccontext
|
||||
opts.onRequest = [
|
||||
async ({ options }) => {
|
||||
if (security) {
|
||||
await setAuthParams({
|
||||
auth: opts.auth,
|
||||
headers: options.headers,
|
||||
query: options.query,
|
||||
security,
|
||||
});
|
||||
}
|
||||
|
||||
if (requestValidator) {
|
||||
await requestValidator({
|
||||
...options,
|
||||
// @ts-expect-error
|
||||
body: options.rawBody,
|
||||
});
|
||||
}
|
||||
},
|
||||
...opts.onRequest,
|
||||
];
|
||||
}
|
||||
|
||||
if (responseTransformer || responseValidator) {
|
||||
opts.onResponse = [
|
||||
...opts.onResponse,
|
||||
async ({ options, response }) => {
|
||||
if (options.responseType && options.responseType !== 'json') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (responseValidator) {
|
||||
await responseValidator(response._data);
|
||||
}
|
||||
|
||||
if (responseTransformer) {
|
||||
response._data = await responseTransformer(response._data);
|
||||
}
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// remove Content-Type header if body is empty to avoid sending invalid requests
|
||||
if (opts.body === undefined || opts.body === '') {
|
||||
opts.headers.delete('Content-Type');
|
||||
}
|
||||
|
||||
const fetchFn = opts.$fetch;
|
||||
|
||||
if (composable === '$fetch') {
|
||||
return executeFetchFn(
|
||||
// @ts-expect-error
|
||||
opts,
|
||||
fetchFn,
|
||||
);
|
||||
}
|
||||
|
||||
if (composable === 'useFetch' || composable === 'useLazyFetch') {
|
||||
opts.rawBody = opts.body;
|
||||
const bodyParams = reactive({
|
||||
body: opts.body,
|
||||
bodySerializer: opts.bodySerializer,
|
||||
});
|
||||
const body = ref(serializeBody({ ...opts, body: toValue(opts.body) }));
|
||||
opts.body = body;
|
||||
watch(bodyParams, (changed) => {
|
||||
body.value = serializeBody(changed);
|
||||
});
|
||||
return composable === 'useLazyFetch'
|
||||
? useLazyFetch(() => buildUrl(opts), { ...opts, ...asyncDataOptions })
|
||||
: useFetch(() => buildUrl(opts), { ...opts, ...asyncDataOptions });
|
||||
}
|
||||
|
||||
const handler: any = () =>
|
||||
executeFetchFn(
|
||||
// @ts-expect-error
|
||||
opts,
|
||||
fetchFn,
|
||||
);
|
||||
|
||||
if (composable === 'useAsyncData') {
|
||||
return key
|
||||
? useAsyncData(key, handler, asyncDataOptions)
|
||||
: useAsyncData(handler, asyncDataOptions);
|
||||
}
|
||||
|
||||
if (composable === 'useLazyAsyncData') {
|
||||
return key
|
||||
? useLazyAsyncData(key, handler, asyncDataOptions)
|
||||
: useLazyAsyncData(handler, asyncDataOptions);
|
||||
}
|
||||
|
||||
return undefined as any;
|
||||
};
|
||||
|
||||
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({
|
||||
...unwrapRefs(opts),
|
||||
body: opts.body as BodyInit | null | undefined,
|
||||
method,
|
||||
onRequest: undefined,
|
||||
serializedBody: getValidRequestBody(opts) as BodyInit | null | undefined,
|
||||
signal: unwrapRefs(opts.signal) as AbortSignal,
|
||||
url,
|
||||
});
|
||||
};
|
||||
|
||||
const _buildUrl: Client['buildUrl'] = (options) =>
|
||||
buildUrl({ ..._config, ...options } as typeof options);
|
||||
|
||||
return {
|
||||
buildUrl: _buildUrl,
|
||||
connect: makeMethodFn('CONNECT'),
|
||||
delete: makeMethodFn('DELETE'),
|
||||
get: makeMethodFn('GET'),
|
||||
getConfig,
|
||||
head: makeMethodFn('HEAD'),
|
||||
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;
|
||||
};
|
||||
24
app/openapi/generated/client/index.ts
Normal file
24
app/openapi/generated/client/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
export type { Auth } from '../core/auth.gen';
|
||||
export type { QuerySerializerOptions } from '../core/bodySerializer.gen';
|
||||
export {
|
||||
formDataBodySerializer,
|
||||
jsonBodySerializer,
|
||||
urlSearchParamsBodySerializer,
|
||||
} from '../core/bodySerializer.gen';
|
||||
export { buildClientParams } from '../core/params.gen';
|
||||
export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen';
|
||||
export { createClient } from './client.gen';
|
||||
export type {
|
||||
Client,
|
||||
ClientOptions,
|
||||
Composable,
|
||||
Config,
|
||||
CreateClientConfig,
|
||||
Options,
|
||||
RequestOptions,
|
||||
RequestResult,
|
||||
TDataShape,
|
||||
} from './types.gen';
|
||||
export { createConfig } from './utils.gen';
|
||||
191
app/openapi/generated/client/types.gen.ts
Normal file
191
app/openapi/generated/client/types.gen.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import type {
|
||||
AsyncDataOptions,
|
||||
useAsyncData,
|
||||
useFetch,
|
||||
UseFetchOptions,
|
||||
useLazyAsyncData,
|
||||
useLazyFetch,
|
||||
} from 'nuxt/app';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import type { Auth } from '../core/auth.gen';
|
||||
import type { QuerySerializerOptions } from '../core/bodySerializer.gen';
|
||||
import type {
|
||||
ServerSentEventsOptions,
|
||||
ServerSentEventsResult,
|
||||
} from '../core/serverSentEvents.gen';
|
||||
import type { Client as CoreClient, Config as CoreConfig } from '../core/types.gen';
|
||||
|
||||
export type ArraySeparatorStyle = ArrayStyle | MatrixStyle;
|
||||
type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
|
||||
type MatrixStyle = 'label' | 'matrix' | 'simple';
|
||||
export type ObjectSeparatorStyle = ObjectStyle | MatrixStyle;
|
||||
type ObjectStyle = 'form' | 'deepObject';
|
||||
|
||||
export type QuerySerializer = (query: Parameters<Client['buildUrl']>[0]['query']) => string;
|
||||
|
||||
type WithRefs<TData> = {
|
||||
[K in keyof TData]: NonNullable<TData[K]> extends object
|
||||
? WithRefs<NonNullable<TData[K]>> | Ref<NonNullable<TData[K]>> | Extract<TData[K], null>
|
||||
: NonNullable<TData[K]> | Ref<NonNullable<TData[K]>> | Extract<TData[K], null>;
|
||||
};
|
||||
|
||||
// copied from Nuxt
|
||||
export type KeysOf<T> = Array<T extends T ? (keyof T extends string ? keyof T : never) : never>;
|
||||
|
||||
export interface Config<T extends ClientOptions = ClientOptions>
|
||||
extends
|
||||
Omit<FetchOptions<unknown>, 'baseURL' | 'body' | 'headers' | 'method' | 'query'>,
|
||||
WithRefs<Pick<FetchOptions<unknown>, 'query'>>,
|
||||
Omit<CoreConfig, 'querySerializer'> {
|
||||
/**
|
||||
* Base URL for all requests made by this client.
|
||||
*/
|
||||
baseURL?: T['baseURL'];
|
||||
/**
|
||||
* A function for serializing request query parameters. By default, arrays
|
||||
* will be exploded in form style, objects will be exploded in deepObject
|
||||
* style, and reserved characters are percent-encoded.
|
||||
*
|
||||
* {@link https://swagger.io/docs/specification/serialization/#query View examples}
|
||||
*/
|
||||
querySerializer?: QuerySerializer | QuerySerializerOptions;
|
||||
}
|
||||
|
||||
export interface RequestOptions<
|
||||
TComposable extends Composable = '$fetch',
|
||||
ResT = unknown,
|
||||
DefaultT = undefined,
|
||||
Url extends string = string,
|
||||
>
|
||||
extends
|
||||
Config,
|
||||
WithRefs<{
|
||||
path?: FetchOptions<unknown>['query'];
|
||||
query?: FetchOptions<unknown>['query'];
|
||||
}>,
|
||||
Pick<
|
||||
ServerSentEventsOptions<ResT>,
|
||||
| 'onSseError'
|
||||
| 'onSseEvent'
|
||||
| 'sseDefaultRetryDelay'
|
||||
| 'sseMaxRetryAttempts'
|
||||
| 'sseMaxRetryDelay'
|
||||
> {
|
||||
asyncDataOptions?: AsyncDataOptions<ResT, ResT, KeysOf<ResT>, DefaultT>;
|
||||
/**
|
||||
* Any body that you want to add to your request.
|
||||
*
|
||||
* {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
|
||||
*/
|
||||
body?: NonNullable<unknown> | Ref<NonNullable<unknown>> | null;
|
||||
composable?: TComposable;
|
||||
key?: string;
|
||||
rawBody?: NonNullable<unknown> | Ref<NonNullable<unknown>> | null;
|
||||
/**
|
||||
* Security mechanism(s) to use for the request.
|
||||
*/
|
||||
security?: ReadonlyArray<Auth>;
|
||||
url: Url;
|
||||
}
|
||||
|
||||
export type RequestResult<
|
||||
TComposable extends Composable,
|
||||
ResT,
|
||||
TError,
|
||||
> = TComposable extends '$fetch'
|
||||
? ReturnType<typeof $fetch<ResT>>
|
||||
: TComposable extends 'useAsyncData'
|
||||
? ReturnType<typeof useAsyncData<ResT | null, TError>>
|
||||
: TComposable extends 'useFetch'
|
||||
? ReturnType<typeof useFetch<ResT | null, TError>>
|
||||
: TComposable extends 'useLazyAsyncData'
|
||||
? ReturnType<typeof useLazyAsyncData<ResT | null, TError>>
|
||||
: TComposable extends 'useLazyFetch'
|
||||
? ReturnType<typeof useLazyFetch<ResT | null, TError>>
|
||||
: never;
|
||||
|
||||
export interface ClientOptions {
|
||||
baseURL?: string;
|
||||
}
|
||||
|
||||
type MethodFn = <
|
||||
TComposable extends Composable = '$fetch',
|
||||
ResT = unknown,
|
||||
TError = unknown,
|
||||
DefaultT = undefined,
|
||||
>(
|
||||
options: Omit<RequestOptions<TComposable, ResT, DefaultT>, 'method'>,
|
||||
) => RequestResult<TComposable, ResT, TError>;
|
||||
|
||||
type SseFn = <
|
||||
TComposable extends Composable = '$fetch',
|
||||
ResT = unknown,
|
||||
TError = unknown,
|
||||
DefaultT = undefined,
|
||||
>(
|
||||
options: Omit<RequestOptions<TComposable, ResT, DefaultT>, 'method'>,
|
||||
) => Promise<ServerSentEventsResult<RequestResult<TComposable, ResT, TError>>>;
|
||||
|
||||
type RequestFn = <
|
||||
TComposable extends Composable = '$fetch',
|
||||
ResT = unknown,
|
||||
TError = unknown,
|
||||
DefaultT = undefined,
|
||||
>(
|
||||
options: Omit<RequestOptions<TComposable, ResT, DefaultT>, 'method'> &
|
||||
Pick<Required<RequestOptions<TComposable, ResT, DefaultT>>, 'method'>,
|
||||
) => RequestResult<TComposable, ResT, TError>;
|
||||
|
||||
/**
|
||||
* 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?: FetchOptions<unknown>['query'];
|
||||
query?: FetchOptions<unknown>['query'];
|
||||
url: string;
|
||||
}
|
||||
|
||||
export type BuildUrlOptions<
|
||||
TData extends Omit<TDataShape, 'headers'> = Omit<TDataShape, 'headers'>,
|
||||
> = Pick<WithRefs<TData>, 'path' | 'query'> &
|
||||
Pick<TData, 'url'> &
|
||||
Pick<Options<'$fetch', TData>, 'baseURL' | 'querySerializer'>;
|
||||
|
||||
type BuildUrlFn = <TData extends Omit<TDataShape, 'headers'>>(
|
||||
options: BuildUrlOptions<TData>,
|
||||
) => string;
|
||||
|
||||
export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn, SseFn>;
|
||||
|
||||
type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
||||
export type Options<
|
||||
TComposable extends Composable = '$fetch',
|
||||
TData extends TDataShape = TDataShape,
|
||||
ResT = unknown,
|
||||
DefaultT = undefined,
|
||||
> = OmitKeys<RequestOptions<TComposable, ResT, DefaultT>, 'body' | 'path' | 'query' | 'url'> &
|
||||
([TData] extends [never] ? unknown : WithRefs<Omit<TData, 'url'>>);
|
||||
|
||||
type FetchOptions<TData> = Omit<UseFetchOptions<TData, TData>, keyof AsyncDataOptions<TData>>;
|
||||
|
||||
export type Composable =
|
||||
| '$fetch'
|
||||
| 'useAsyncData'
|
||||
| 'useFetch'
|
||||
| 'useLazyAsyncData'
|
||||
| 'useLazyFetch';
|
||||
390
app/openapi/generated/client/utils.gen.ts
Normal file
390
app/openapi/generated/client/utils.gen.ts
Normal file
@@ -0,0 +1,390 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import type { ComputedRef, Ref } from 'vue';
|
||||
import { isRef, toValue, unref } from 'vue';
|
||||
|
||||
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 type {
|
||||
ArraySeparatorStyle,
|
||||
BuildUrlOptions,
|
||||
Client,
|
||||
ClientOptions,
|
||||
Config,
|
||||
QuerySerializer,
|
||||
RequestOptions,
|
||||
} from './types.gen';
|
||||
|
||||
type PathSerializer = Pick<Required<BuildUrlOptions>, 'path' | 'url'>;
|
||||
|
||||
const PATH_PARAM_RE = /\{[^{}]+\}/g;
|
||||
|
||||
type MaybeArray<T> = T | T[];
|
||||
|
||||
const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
|
||||
let url = _url;
|
||||
const matches = _url.match(PATH_PARAM_RE);
|
||||
if (matches) {
|
||||
for (const match of matches) {
|
||||
let explode = false;
|
||||
let name = match.substring(1, match.length - 1);
|
||||
let style: ArraySeparatorStyle = 'simple';
|
||||
|
||||
if (name.endsWith('*')) {
|
||||
explode = true;
|
||||
name = name.substring(0, name.length - 1);
|
||||
}
|
||||
|
||||
if (name.startsWith('.')) {
|
||||
name = name.substring(1);
|
||||
style = 'label';
|
||||
} else if (name.startsWith(';')) {
|
||||
name = name.substring(1);
|
||||
style = 'matrix';
|
||||
}
|
||||
|
||||
const value = toValue((toValue(path) as Record<string, unknown> | undefined)?.[name]);
|
||||
|
||||
if (value === undefined || value === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof value === 'object') {
|
||||
url = url.replace(
|
||||
match,
|
||||
serializeObjectParam({
|
||||
explode,
|
||||
name,
|
||||
style,
|
||||
value: value as Record<string, unknown>,
|
||||
valueOnly: true,
|
||||
}),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (style === 'matrix') {
|
||||
url = url.replace(
|
||||
match,
|
||||
`;${serializePrimitiveParam({
|
||||
name,
|
||||
value: value as string,
|
||||
})}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const replaceValue = encodeURIComponent(
|
||||
style === 'label' ? `.${value as string}` : (value as string),
|
||||
);
|
||||
url = url.replace(match, replaceValue);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
export const createQuerySerializer = <T = unknown>({
|
||||
parameters = {},
|
||||
...args
|
||||
}: QuerySerializerOptions = {}) => {
|
||||
const querySerializer = (queryParams: T) => {
|
||||
const search: string[] = [];
|
||||
const qParams = toValue(queryParams);
|
||||
if (qParams && typeof qParams === 'object') {
|
||||
for (const name in qParams) {
|
||||
const value = toValue(qParams[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;
|
||||
};
|
||||
|
||||
const checkForExistence = (
|
||||
options: Pick<RequestOptions, 'auth' | 'query'> & {
|
||||
headers: Headers;
|
||||
},
|
||||
name?: string,
|
||||
): boolean => {
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
options.headers.has(name) ||
|
||||
(toValue(options.query) as Record<string, unknown> | undefined)?.[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 = {};
|
||||
}
|
||||
const queryValue = toValue(options.query) as Record<string, unknown> | undefined;
|
||||
if (queryValue) {
|
||||
queryValue[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) => {
|
||||
const url = 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,
|
||||
});
|
||||
return url;
|
||||
};
|
||||
|
||||
export const getUrl = ({
|
||||
baseUrl,
|
||||
path,
|
||||
query,
|
||||
querySerializer,
|
||||
url: _url,
|
||||
}: Pick<BuildUrlOptions, 'path' | 'query' | 'url'> & {
|
||||
baseUrl?: string;
|
||||
querySerializer: QuerySerializer;
|
||||
}) => {
|
||||
const pathUrl = _url.startsWith('/') ? _url : `/${_url}`;
|
||||
let url = (baseUrl ?? '') + pathUrl;
|
||||
if (path) {
|
||||
url = defaultPathSerializer({ path, url });
|
||||
}
|
||||
let search = query ? querySerializer(query) : '';
|
||||
if (search.startsWith('?')) {
|
||||
search = search.substring(1);
|
||||
}
|
||||
if (search) {
|
||||
url += `?${search}`;
|
||||
}
|
||||
return 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 || typeof header !== 'object') {
|
||||
continue;
|
||||
}
|
||||
|
||||
let h: unknown = header;
|
||||
if (isRef(h)) {
|
||||
h = unref(h);
|
||||
}
|
||||
|
||||
const iterator =
|
||||
h instanceof Headers ? headersEntries(h) : Object.entries(h as Record<string, unknown>);
|
||||
|
||||
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, unwrapRefs(v) as string);
|
||||
}
|
||||
} else if (value !== undefined) {
|
||||
const v = unwrapRefs(value);
|
||||
// assume object headers are meant to be JSON stringified, i.e. their
|
||||
// content value in OpenAPI specification is 'application/json'
|
||||
mergedHeaders.set(key, typeof v === 'object' ? JSON.stringify(v) : (v as string));
|
||||
}
|
||||
}
|
||||
}
|
||||
return mergedHeaders;
|
||||
};
|
||||
|
||||
export const mergeInterceptors = <T>(...args: Array<MaybeArray<T>>): Array<T> =>
|
||||
args.reduce<Array<T>>((acc, item) => {
|
||||
if (typeof item === 'function') {
|
||||
acc.push(item);
|
||||
} else if (Array.isArray(item)) {
|
||||
return acc.concat(item);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
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,
|
||||
querySerializer: defaultQuerySerializer,
|
||||
...override,
|
||||
});
|
||||
|
||||
type UnwrapRefs<T> =
|
||||
T extends Ref<infer V>
|
||||
? V
|
||||
: T extends ComputedRef<infer V>
|
||||
? V
|
||||
: T extends Record<string, unknown> // this doesn't handle functions well
|
||||
? { [K in keyof T]: UnwrapRefs<T[K]> }
|
||||
: T;
|
||||
|
||||
export const unwrapRefs = <T>(value: T): UnwrapRefs<T> => {
|
||||
if (value === null || typeof value !== 'object' || value instanceof Headers) {
|
||||
return (isRef(value) ? unref(value) : value) as UnwrapRefs<T>;
|
||||
}
|
||||
|
||||
if (value instanceof Blob) {
|
||||
return value as UnwrapRefs<T>;
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
return value.map((item) => unwrapRefs(item)) as UnwrapRefs<T>;
|
||||
}
|
||||
|
||||
if (isRef(value)) {
|
||||
return unwrapRefs(unref(value) as T);
|
||||
}
|
||||
|
||||
// unwrap into new object to avoid modifying the source
|
||||
const result: Record<string, unknown> = {};
|
||||
for (const key in value) {
|
||||
result[key] = unwrapRefs(value[key] as T);
|
||||
}
|
||||
return result as UnwrapRefs<T>;
|
||||
};
|
||||
|
||||
export const serializeBody = (
|
||||
opts: Pick<Parameters<Client['request']>[0], 'body' | 'bodySerializer'>,
|
||||
) => {
|
||||
if (opts.body && opts.bodySerializer) {
|
||||
return opts.bodySerializer(opts.body);
|
||||
}
|
||||
return opts.body;
|
||||
};
|
||||
|
||||
export const executeFetchFn = (
|
||||
opts: Omit<Parameters<Client['request']>[0], 'composable'>,
|
||||
fetchFn: Required<Config>['$fetch'],
|
||||
) => {
|
||||
const unwrappedOpts = unwrapRefs(opts);
|
||||
unwrappedOpts.rawBody = unwrappedOpts.body;
|
||||
unwrappedOpts.body = serializeBody(unwrappedOpts);
|
||||
return fetchFn(
|
||||
buildUrl(opts),
|
||||
// @ts-expect-error
|
||||
unwrappedOpts,
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user