@hyper-fetch/core
Version:
Cache, Queue and Persist your requests no matter if you are online or offline!
127 lines (115 loc) • 3.31 kB
text/typescript
import { getAdapterBindings, AdapterInstance, RequestProcessingError } from "adapter";
import { ExtractAdapterExtraType, ExtractAdapterStatusType } from "types";
export const mocker = async <T extends AdapterInstance>({
request,
requestId,
onError,
onResponseEnd,
onTimeoutError,
onRequestEnd,
createAbortListener,
onResponseProgress,
onRequestProgress,
onResponseStart,
onBeforeRequest,
onRequestStart,
onSuccess,
onAbortError,
adapter,
}: Awaited<ReturnType<typeof getAdapterBindings<T>>>) => {
if (!request.unstable_mock) {
throw new RequestProcessingError("Mock should be defined when calling mocker");
}
let thrown = false;
const {
requestTime = 20,
responseTime = 20,
totalUploaded = 1000,
totalDownloaded = 1000,
timeout,
} = request.unstable_mock.config;
const result = await request.unstable_mock.fn({ request, requestId });
const { data, error, status, success = true, extra = request.client.adapter.defaultExtra } = result;
createAbortListener({
status: adapter.systemErrorStatus,
extra: adapter.systemErrorExtra,
onAbort: () => {
thrown = true;
},
});
onBeforeRequest();
onRequestStart();
const progress = (
totalTime: number,
totalSize: number,
progressFunction: typeof onResponseProgress | typeof onRequestProgress,
) =>
new Promise((resolveProgress) => {
if (thrown) {
resolveProgress(true);
return;
}
const interval = 20;
const dataStart = +new Date();
const intervals = Math.ceil(totalTime / interval);
const chunkSize = Math.ceil(totalSize / intervals);
let currentlyLoaded = 0;
const timer = setInterval(function handleProgressInterval() {
if (thrown) {
resolveProgress(true);
clearInterval(timer);
}
const currentTime = Math.min(totalTime, +new Date() - dataStart);
currentlyLoaded += currentlyLoaded + chunkSize >= totalSize ? totalSize - currentlyLoaded : chunkSize;
progressFunction({
total: totalSize,
loaded: currentTime >= totalTime ? totalSize : currentlyLoaded,
});
if (currentTime >= totalTime) {
resolveProgress(true);
clearInterval(timer);
}
}, interval);
});
if (typeof timeout === "number") {
setTimeout(() => {
thrown = true;
onTimeoutError({
status: 0 as ExtractAdapterStatusType<T>,
extra: extra as ExtractAdapterExtraType<T>,
});
}, timeout);
}
if (!thrown) {
await progress(requestTime, totalUploaded, onRequestProgress);
}
if (!thrown) {
onRequestEnd();
onResponseStart();
}
if (!thrown) {
await progress(responseTime, totalDownloaded, onResponseProgress);
}
if (thrown) {
onAbortError({
status: adapter.systemErrorStatus,
extra: adapter.systemErrorExtra,
});
} else if (success || (error && data)) {
onSuccess({
data,
error,
status: status as ExtractAdapterStatusType<T>,
extra: extra as ExtractAdapterExtraType<T>,
});
} else {
onError({
error,
status: status as ExtractAdapterStatusType<T>,
extra: extra as ExtractAdapterExtraType<T>,
});
}
if (!thrown) {
onResponseEnd();
}
};