import type { FetchOptions, FetchRequest } from 'ohmyfetch' import type { TypedInternalResponse } from '@nuxt/nitro' import { hash } from 'ohash' import { computed, isRef, Ref } from 'vue' import type { AsyncDataOptions, _Transform, KeyOfRes } from './asyncData' import { useAsyncData } from './asyncData' export type FetchResult = TypedInternalResponse export type UseFetchOptions< DataT, Transform extends _Transform = _Transform, PickKeys extends KeyOfRes = KeyOfRes > = AsyncDataOptions & FetchOptions & { key?: string } export function useFetch< ResT = void, ReqT extends FetchRequest = FetchRequest, _ResT = ResT extends void ? FetchResult : ResT, Transform extends (res: _ResT) => any = (res: _ResT) => _ResT, PickKeys extends KeyOfRes = KeyOfRes > ( request: Ref | ReqT | (() => ReqT), opts: UseFetchOptions<_ResT, Transform, PickKeys> = {} ) { const key = '$f_' + (opts.key || hash([request, opts])) const _request = computed(() => { let r = request if (typeof r === 'function') { r = r() } return isRef(r) ? r.value : r }) const asyncData = useAsyncData(key, () => { return $fetch(_request.value, opts) as Promise<_ResT> }, { ...opts, watch: [ _request, ...(opts.watch || []) ] }) return asyncData } export function useLazyFetch< ResT = void, ReqT extends string = string, _ResT = ResT extends void ? FetchResult : ResT, Transform extends (res: _ResT) => any = (res: _ResT) => _ResT, PickKeys extends KeyOfRes = KeyOfRes > ( url: ReqT, opts: Omit, 'lazy'> = {} ) { return useFetch(url, { ...opts, lazy: true }) }