@cardbrother/up-fetch
Version:
Advanced fetch client builder for typescript.
90 lines (85 loc) • 2.89 kB
text/typescript
import type { StandardSchemaV1 } from '@standard-schema/spec'
import { resolveOptions } from './resolve-options'
import type {
FetcherOptions,
DefaultOptions,
BaseFetchFn,
FallbackOptions,
} from './types'
import { emptyOptions, validate } from './utils'
export function up<
TFetchFn extends BaseFetchFn,
TDefaultParsedData = any,
TDefaultRawBody = Parameters<FallbackOptions<any>['serializeBody']>[0],
>(
fetchFn: TFetchFn,
getDefaultOptions: (
input: Parameters<TFetchFn>[0],
fetcherOpts: FetcherOptions<TFetchFn, any, any, any>,
ctx?: Parameters<TFetchFn>[2],
) => DefaultOptions<TFetchFn, TDefaultParsedData, TDefaultRawBody> = () =>
emptyOptions,
) {
return async <
TParsedData = TDefaultParsedData,
TSchema extends StandardSchemaV1<
TParsedData,
any
> = StandardSchemaV1<TParsedData>,
TRawBody = TDefaultRawBody,
>(
input: Parameters<TFetchFn>[0],
fetcherOpts: FetcherOptions<
TFetchFn,
TSchema,
TParsedData,
TRawBody
> = emptyOptions,
ctx?: Parameters<TFetchFn>[2],
) => {
let defaultOpts = getDefaultOptions(input, fetcherOpts, ctx)
let options = resolveOptions(input, defaultOpts, fetcherOpts)
await defaultOpts?.onRequest?.(options)
// if (defaultOpts.onRequest && isPromise(defaultOpts.onRequest)) {
// } else {
// defaultOpts.onRequest?.(options)
// }
return fetchFn(options.input, options, ctx)
.catch((error) => {
defaultOpts.onError?.(error, options)
throw error
})
.then(async (response: Response) => {
if (!(await options.reject(response))) {
let parsed: Awaited<TParsedData>
try {
parsed = await options.parseResponse(response, options)
} catch (error: any) {
defaultOpts.onError?.(error, options)
throw error
}
let data: Awaited<StandardSchemaV1.InferOutput<TSchema>>
try {
data = options.schema
? await validate(options.schema, parsed)
: parsed
} catch (error: any) {
defaultOpts.onError?.(error, options)
throw error
}
defaultOpts.onSuccess?.(data, options)
return data
} else {
let respError: any
try {
respError = await options.parseRejected(response, options)
} catch (error: any) {
defaultOpts.onError?.(error, options)
throw error
}
defaultOpts.onError?.(respError, options)
throw respError
}
})
}
}