@hyper-fetch/react
Version:
React hooks and utils for the hyper-fetch
1,434 lines (1,411 loc) • 52.6 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/hooks/use-fetch/use-fetch.hooks.ts
import { useRef as useRef4 } from "react";
import { useDidUpdate as useDidUpdate3, useDidMount as useDidMount2, useWillUnmount as useWillUnmount2 } from "@better-hooks/lifecycle";
import { useDebounce, useThrottle } from "@better-hooks/performance";
import { Request, getRequestKey } from "@hyper-fetch/core";
// src/helpers/use-request-events/use-request-events.hooks.ts
import { useRef } from "react";
import { useWillUnmount } from "@better-hooks/lifecycle";
var useRequestEvents = ({
request,
dispatcher,
logger,
actions,
setCacheData,
getIsDataProcessing
}) => {
const { responseMapper } = request;
const { cache, requestManager } = request.client;
const onSuccessCallback = useRef(null);
const onErrorCallback = useRef(null);
const onAbortCallback = useRef(null);
const onOfflineErrorCallback = useRef(null);
const onFinishedCallback = useRef(null);
const onRequestStartCallback = useRef(null);
const onResponseStartCallback = useRef(null);
const onDownloadProgressCallback = useRef(null);
const onUploadProgressCallback = useRef(null);
const lifecycleEvents = useRef(/* @__PURE__ */ new Map());
const dataEvents = useRef(null);
const removeLifecycleListener = (requestId) => {
const event = lifecycleEvents.current.get(requestId);
event == null ? void 0 : event.unmount();
lifecycleEvents.current.delete(requestId);
};
const clearLifecycleListeners = () => {
const events = lifecycleEvents.current;
const listeners = Array.from(events.values());
listeners.forEach((value) => {
value.unmount();
});
events.clear();
};
const handleResponseCallbacks = (cmd, response, details) => {
var _a, _b, _c, _d, _e;
const { data, error, success } = response;
const { isOffline, isCanceled } = details;
if (request.offline && isOffline && !success) {
logger.debug("Performing offline error callback", { data, details });
(_a = onOfflineErrorCallback.current) == null ? void 0 : _a.call(onOfflineErrorCallback, { response: error, request: cmd, details });
} else if (isCanceled) {
logger.debug("Performing abort callback", { data, details });
(_b = onAbortCallback.current) == null ? void 0 : _b.call(onAbortCallback, { response: error, request: cmd, details });
} else if (success) {
logger.debug("Performing success callback", { data, details });
(_c = onSuccessCallback.current) == null ? void 0 : _c.call(onSuccessCallback, { response: data, request: cmd, details });
} else {
logger.debug("Performing error callback", { data, details });
(_d = onErrorCallback.current) == null ? void 0 : _d.call(onErrorCallback, { response: error, request: cmd, details });
}
(_e = onFinishedCallback.current) == null ? void 0 : _e.call(onFinishedCallback, { response, request: cmd, details });
};
const handleGetLoadingEvent = (req) => {
return ({ loading }) => {
const isProcessing = getIsDataProcessing(req.cacheKey);
if (isProcessing)
return;
const canDisableLoading = !loading && !dispatcher.hasRunningRequests(req.queueKey);
if (loading || canDisableLoading) {
actions.setLoading(loading, false);
}
};
};
const handleDownloadProgress = (progress, details) => {
var _a;
(_a = onDownloadProgressCallback.current) == null ? void 0 : _a.call(onDownloadProgressCallback, progress, details);
};
const handleUploadProgress = (progress, details) => {
var _a;
(_a = onUploadProgressCallback.current) == null ? void 0 : _a.call(onUploadProgressCallback, progress, details);
};
const handleRequestStart = (cmd) => {
return (details) => {
var _a;
(_a = onRequestStartCallback.current) == null ? void 0 : _a.call(onRequestStartCallback, { request: cmd, details });
};
};
const handleResponseStart = (cmd) => {
return (details) => {
var _a;
(_a = onResponseStartCallback.current) == null ? void 0 : _a.call(onResponseStartCallback, { request: cmd, details });
};
};
const handleResponse = (req) => {
return (response, details) => {
const data = responseMapper ? responseMapper(response) : response;
if (data instanceof Promise) {
return (() => __async(void 0, null, function* () {
const promiseData = yield data;
handleResponseCallbacks(req, promiseData, details);
}))();
}
return handleResponseCallbacks(req, data, details);
};
};
const handleRemove = ({ requestId }) => {
removeLifecycleListener(requestId);
};
const clearCacheDataListener = () => {
var _a;
(_a = dataEvents.current) == null ? void 0 : _a.unmount();
dataEvents.current = null;
};
const addCacheDataListener = (req) => {
const loadingUnmount = requestManager.events.onLoading(req.queueKey, handleGetLoadingEvent(req));
const getResponseUnmount = cache.events.onData(
req.cacheKey,
setCacheData
);
const unmount = () => {
loadingUnmount();
getResponseUnmount();
};
clearCacheDataListener();
dataEvents.current = { unmount };
return unmount;
};
const addLifecycleListeners = (req, requestId) => {
if (!requestId) {
clearLifecycleListeners();
const { queueKey, cacheKey } = req;
const requestStartUnmount2 = requestManager.events.onRequestStart(queueKey, handleRequestStart(req));
const responseStartUnmount2 = requestManager.events.onResponseStart(queueKey, handleResponseStart(req));
const uploadUnmount2 = requestManager.events.onUploadProgress(queueKey, handleUploadProgress);
const downloadUnmount2 = requestManager.events.onDownloadProgress(queueKey, handleDownloadProgress);
const responseUnmount2 = requestManager.events.onResponse(cacheKey, handleResponse(req));
const unmount2 = () => {
downloadUnmount2();
uploadUnmount2();
requestStartUnmount2();
responseStartUnmount2();
responseUnmount2();
};
lifecycleEvents.current.set(queueKey, { unmount: unmount2 });
return unmount2;
}
const requestRemove = requestManager.events.onRemoveById(requestId, handleRemove);
const requestStartUnmount = requestManager.events.onRequestStartById(requestId, handleRequestStart(req));
const responseStartUnmount = requestManager.events.onResponseStartById(requestId, handleResponseStart(req));
const responseUnmount = requestManager.events.onResponseById(requestId, handleResponse(req));
const uploadUnmount = requestManager.events.onUploadProgressById(requestId, handleUploadProgress);
const downloadUnmount = requestManager.events.onDownloadProgressById(requestId, handleDownloadProgress);
const unmount = () => {
requestRemove();
downloadUnmount();
uploadUnmount();
requestStartUnmount();
responseStartUnmount();
responseUnmount();
};
lifecycleEvents.current.set(requestId, { unmount });
return unmount;
};
const abort = () => {
const { abortKey } = request;
const requests = dispatcher.getAllRunningRequest();
requests.forEach((requestData) => {
if (requestData.request.abortKey === abortKey) {
dispatcher.delete(requestData.request.queueKey, requestData.requestId, abortKey);
}
});
};
useWillUnmount(() => {
clearLifecycleListeners();
clearCacheDataListener();
});
return [
{
abort,
onSuccess: (callback) => {
onSuccessCallback.current = callback;
},
onError: (callback) => {
onErrorCallback.current = callback;
},
onAbort: (callback) => {
onAbortCallback.current = callback;
},
onOfflineError: (callback) => {
onOfflineErrorCallback.current = callback;
},
onFinished: (callback) => {
onFinishedCallback.current = callback;
},
onRequestStart: (callback) => {
onRequestStartCallback.current = callback;
},
onResponseStart: (callback) => {
onResponseStartCallback.current = callback;
},
onDownloadProgress: (callback) => {
onDownloadProgressCallback.current = callback;
},
onUploadProgress: (callback) => {
onUploadProgressCallback.current = callback;
}
},
{
addCacheDataListener,
clearCacheDataListener,
addLifecycleListeners,
removeLifecycleListener,
clearLifecycleListeners
}
];
};
// src/helpers/use-tracked-state/use-tracked-state.constants.ts
var initialState = {
data: null,
error: null,
status: null,
extra: null,
success: null,
loading: false,
retries: 0,
timestamp: null
};
// src/helpers/use-tracked-state/use-tracked-state.hooks.ts
import { useRef as useRef2 } from "react";
import { useDidUpdate, useForceUpdate } from "@better-hooks/lifecycle";
// src/utils/deep-equal.utils.ts
var isEmpty = (value) => {
const valueType = Object.prototype.toString.call(value);
if (Array.isArray(value))
return !value.length;
if (typeof value === "object" && value !== null && valueType === "[object Object]")
return !Object.keys(value).length;
return false;
};
var isEqual = (firstValue, secondValue) => {
if (firstValue === secondValue)
return true;
try {
const firstValueType = Object.prototype.toString.call(firstValue);
const secondValueType = Object.prototype.toString.call(secondValue);
const firstType = typeof firstValue;
const secondType = typeof secondValue;
const isType = (type) => firstType === type && secondType === type;
const isTypeValue = (type) => firstValueType === type && secondValueType === type;
if (firstValueType !== secondValueType)
return false;
if (firstValue === null && secondValue === null)
return true;
if (isType("number") && Number.isNaN(firstValue) && Number.isNaN(secondValue))
return true;
if (isEmpty(firstValue) && isEmpty(secondValue))
return true;
if (Array.isArray(firstValue) && Array.isArray(secondValue)) {
if (firstValue.length !== secondValue.length)
return false;
return !firstValue.some((element, i) => !isEqual(element, secondValue[i]));
}
if (isType("object") && isTypeValue("[object Object]")) {
if (Object.keys(firstValue).length !== Object.keys(secondValue).length)
return false;
return !Object.entries(firstValue).some(
([key, value]) => !isEqual(value, secondValue[key])
);
}
if (firstValue instanceof Date && secondValue instanceof Date) {
return +firstValue === +secondValue;
}
return firstValue === secondValue;
} catch (err) {
console.error(err);
return false;
}
};
// src/utils/bounce.utils.ts
var getBounceData = (bounceData) => {
return __spreadValues(__spreadValues({}, bounceData), { throttle: void 0, debounce: void 0 });
};
// src/helpers/use-tracked-state/use-tracked-state.utils.ts
var getDetailsState = (state, details) => {
return __spreadValues({
retries: (state == null ? void 0 : state.retries) || 0,
timestamp: +new Date(),
isCanceled: false,
isOffline: false
}, details);
};
var isStaleCacheData = (cacheTime, cacheTimestamp) => {
if (!cacheTimestamp)
return true;
return +new Date() > +cacheTimestamp + cacheTime;
};
var getValidCacheData = (request, initialData, cacheData) => {
const isStale = isStaleCacheData(request.cacheTime, cacheData == null ? void 0 : cacheData.timestamp);
if (!isStale && cacheData) {
return cacheData;
}
if (initialData) {
return __spreadProps(__spreadValues(__spreadValues({
data: null,
error: null,
status: null,
success: null,
extra: null
}, initialData || {}), getDetailsState()), {
cacheTime: 1e3,
clearKey: request.client.cache.clearKey,
garbageCollection: request.garbageCollection
});
}
return null;
};
var getTimestamp = (timestamp) => {
return timestamp ? new Date(timestamp) : null;
};
var getIsInitiallyLoading = ({
queryKey,
dispatcher,
hasState,
revalidate,
disabled
}) => {
if (!revalidate && hasState) {
return false;
}
const queue = dispatcher.getQueue(queryKey);
const isInitiallyLoading = dispatcher.hasRunningRequests(queryKey) || !queue.stopped && disabled === false;
return isInitiallyLoading;
};
var getInitialState = ({
initialResponse,
dispatcher,
request,
disabled,
revalidate
}) => {
const { client, cacheKey, responseMapper } = request;
const { cache } = client;
const cacheData = cache.get(cacheKey);
const cacheState = getValidCacheData(request, initialResponse, cacheData);
const initialLoading = getIsInitiallyLoading({
queryKey: request.queueKey,
dispatcher,
disabled,
revalidate,
hasState: !!cacheState
});
if (cacheState) {
const mappedData = responseMapper ? responseMapper(cacheState) : cacheState;
if (mappedData instanceof Promise) {
return initialState;
}
return {
data: mappedData.data,
error: mappedData.error,
status: mappedData.status,
success: mappedData.success,
extra: mappedData.extra,
retries: cacheState.retries,
timestamp: getTimestamp(cacheState.timestamp),
loading: initialLoading
};
}
return {
data: initialState.data,
error: initialState.error,
status: initialState.status,
success: initialState.success,
extra: request.client.defaultExtra,
retries: initialState.retries,
timestamp: getTimestamp(initialState.timestamp),
loading: initialLoading
};
};
// src/helpers/use-tracked-state/use-tracked-state.hooks.ts
var useTrackedState = ({
request,
dispatcher,
initialData,
deepCompare,
dependencyTracking,
defaultCacheEmitting = true,
disabled,
revalidate
}) => {
const { client, cacheKey, queueKey, cacheTime, responseMapper } = request;
const { cache, requestManager } = client;
const forceUpdate = useForceUpdate();
const state = useRef2(
getInitialState({ initialResponse: initialData, dispatcher, request, disabled })
);
const renderKeys = useRef2([]);
const isProcessingData = useRef2("");
const getStaleStatus = () => {
const cacheData = cache.get(cacheKey);
return !cacheData || isStaleCacheData(cacheTime, cacheData == null ? void 0 : cacheData.timestamp);
};
const renderKeyTrigger = (keys) => {
const shouldRerender = renderKeys.current.some((renderKey) => keys.includes(renderKey));
if (shouldRerender)
forceUpdate();
};
const setRenderKey = (renderKey) => {
if (!renderKeys.current.includes(renderKey)) {
renderKeys.current.push(renderKey);
}
};
useDidUpdate(
() => {
state.current.loading = dispatcher.hasRunningRequests(queueKey);
const cacheData = cache.get(cacheKey);
const cacheState = getValidCacheData(request, initialData, cacheData);
state.current.loading = getIsInitiallyLoading({
queryKey: request.queueKey,
dispatcher,
disabled,
revalidate,
hasState: !!cacheState
});
const hasInitialState = isEqual(initialData == null ? void 0 : initialData.data, state.current.data);
const hasState = !!(state.current.data || state.current.error) && !hasInitialState;
const shouldLoadInitialCache = !hasState && !!state.current.data;
const shouldRemovePreviousData = hasState && !state.current.data;
if (cacheState || shouldLoadInitialCache || shouldRemovePreviousData) {
setCacheData(cacheState);
}
},
[cacheKey, queueKey],
true
);
useDidUpdate(
() => {
const handleDependencyTracking = () => {
if (!dependencyTracking) {
Object.keys(state.current).forEach((key) => setRenderKey(key));
}
};
handleDependencyTracking();
},
[dependencyTracking],
true
);
const handleCompare = (firstValue, secondValue) => {
if (typeof deepCompare === "function") {
return deepCompare(firstValue, secondValue);
}
if (deepCompare) {
return isEqual(firstValue, secondValue);
}
return false;
};
const handleCacheData = (cacheData) => {
const newStateValues = {
data: cacheData.data,
error: cacheData.error,
status: cacheData.status,
success: cacheData.success,
extra: cacheData.extra,
retries: cacheData.retries,
timestamp: new Date(cacheData.timestamp),
loading: dispatcher.hasRunningRequests(queueKey)
};
const changedKeys = Object.keys(newStateValues).filter((key) => {
const keyValue = key;
const firstValue = state.current[keyValue];
const secondValue = newStateValues[keyValue];
return !handleCompare(firstValue, secondValue);
});
state.current = __spreadValues(__spreadValues({}, state.current), newStateValues);
renderKeyTrigger(changedKeys);
};
const setIsDataProcessing = ({
processingCacheKey,
isProcessing
}) => {
if (isProcessing) {
isProcessingData.current = processingCacheKey;
} else if (isProcessingData.current === cacheKey) {
isProcessingData.current = "";
}
};
const getIsDataProcessing = (processingCacheKey) => {
return isProcessingData.current === processingCacheKey;
};
const setCacheData = (cacheData) => {
setIsDataProcessing({ processingCacheKey: cacheKey, isProcessing: true });
const data = responseMapper ? responseMapper(cacheData) : cacheData;
if (data instanceof Promise) {
return (() => __async(void 0, null, function* () {
const promiseData = yield data;
handleCacheData(__spreadValues(__spreadValues({}, cacheData), promiseData));
setIsDataProcessing({ processingCacheKey: cacheKey, isProcessing: false });
}))();
}
setIsDataProcessing({ processingCacheKey: cacheKey, isProcessing: false });
return handleCacheData(__spreadValues(__spreadValues({}, cacheData), data));
};
const actions = {
setData: (data, emitToCache = defaultCacheEmitting) => {
if (emitToCache) {
const currentState = state.current;
cache.set(request, __spreadProps(__spreadValues(__spreadValues({}, currentState), getDetailsState(state.current)), { success: true, data }));
} else {
state.current.data = data;
renderKeyTrigger(["data"]);
}
},
setError: (error, emitToCache = defaultCacheEmitting) => {
if (emitToCache) {
const currentState = state.current;
cache.set(request, __spreadProps(__spreadValues(__spreadValues({}, currentState), getDetailsState(state.current)), { success: false, error }));
} else {
state.current.error = error;
renderKeyTrigger(["error"]);
}
},
setLoading: (loading, emitToHooks = true) => {
if (emitToHooks) {
requestManager.events.emitLoading(queueKey, "", {
queueKey,
requestId: "",
loading,
isRetry: false,
isOffline: false
});
} else if (loading !== state.current.loading) {
state.current.loading = loading;
renderKeyTrigger(["loading"]);
}
},
setStatus: (status, emitToCache = defaultCacheEmitting) => {
if (emitToCache) {
const currentState = state.current;
cache.set(request, __spreadProps(__spreadValues(__spreadValues({}, currentState), getDetailsState(state.current)), { status }));
} else {
state.current.status = status;
renderKeyTrigger(["status"]);
}
},
setSuccess: (success, emitToCache = defaultCacheEmitting) => {
if (emitToCache) {
const currentState = state.current;
cache.set(request, __spreadProps(__spreadValues(__spreadValues({}, currentState), getDetailsState(state.current)), { success }));
} else {
state.current.success = success;
renderKeyTrigger(["success"]);
}
},
setExtra: (extra, emitToCache = defaultCacheEmitting) => {
if (emitToCache) {
const currentState = state.current;
cache.set(request, __spreadProps(__spreadValues(__spreadValues({}, currentState), getDetailsState(state.current)), { extra }));
} else {
state.current.extra = extra;
renderKeyTrigger(["extra"]);
}
},
setRetries: (retries, emitToCache = defaultCacheEmitting) => {
if (emitToCache) {
const currentState = state.current;
cache.set(request, __spreadValues(__spreadValues({}, currentState), getDetailsState(state.current, { retries })));
} else {
state.current.retries = retries;
renderKeyTrigger(["retries"]);
}
},
setTimestamp: (timestamp, emitToCache = defaultCacheEmitting) => {
if (emitToCache) {
const currentState = state.current;
cache.set(request, __spreadValues(__spreadValues({}, currentState), getDetailsState(state.current, { timestamp: +timestamp })));
} else {
state.current.timestamp = timestamp;
renderKeyTrigger(["timestamp"]);
}
}
};
return [state.current, actions, { setRenderKey, setCacheData, getStaleStatus, getIsDataProcessing }];
};
// src/helpers/use-socket-state/use-socket-state.hooks.ts
import { useRef as useRef3 } from "react";
import { useDidMount, useDidUpdate as useDidUpdate2, useForceUpdate as useForceUpdate2 } from "@better-hooks/lifecycle";
var useSocketState = (socket, { dependencyTracking }) => {
const forceUpdate = useForceUpdate2();
const onOpenCallback = useRef3(null);
const onCloseCallback = useRef3(null);
const onErrorCallback = useRef3(null);
const onConnectingCallback = useRef3(null);
const onReconnectingCallback = useRef3(null);
const onReconnectingStopCallback = useRef3(null);
const state = useRef3(initialSocketState);
const renderKeys = useRef3([]);
const renderKeyTrigger = (keys) => {
const shouldRerender = renderKeys.current.some((renderKey) => keys.includes(renderKey));
if (shouldRerender)
forceUpdate();
};
const setRenderKey = (renderKey) => {
if (!renderKeys.current.includes(renderKey)) {
renderKeys.current.push(renderKey);
}
};
useDidUpdate2(
() => {
const handleDependencyTracking = () => {
if (!dependencyTracking) {
Object.keys(state.current).forEach((key) => setRenderKey(key));
}
};
handleDependencyTracking();
},
[dependencyTracking],
true
);
const actions = {
setData: (data) => {
state.current.data = data;
renderKeyTrigger(["data"]);
},
setConnected: (connected) => {
state.current.connected = connected;
renderKeyTrigger(["data"]);
},
setConnecting: (connecting) => {
state.current.connecting = connecting;
renderKeyTrigger(["data"]);
},
setTimestamp: (timestamp) => {
state.current.timestamp = timestamp;
renderKeyTrigger(["timestamp"]);
}
};
const callbacks = {
onOpen: (callback) => {
onOpenCallback.current = callback;
},
onClose: (callback) => {
onCloseCallback.current = callback;
},
onError: (callback) => {
onErrorCallback.current = callback;
},
onConnecting: (callback) => {
onConnectingCallback.current = callback;
},
onReconnecting: (callback) => {
onReconnectingCallback.current = callback;
},
onReconnectingStop: (callback) => {
onReconnectingStopCallback.current = callback;
}
};
useDidMount(() => {
const umountOnError = socket.events.onError((event) => {
var _a;
(_a = onErrorCallback.current) == null ? void 0 : _a.call(onErrorCallback, event);
});
const umountOnConnecting = socket.events.onConnecting(() => {
var _a;
actions.setConnecting(true);
(_a = onConnectingCallback.current) == null ? void 0 : _a.call(onConnectingCallback);
});
const umountOnOpen = socket.events.onOpen(() => {
var _a;
actions.setConnected(true);
(_a = onOpenCallback.current) == null ? void 0 : _a.call(onOpenCallback);
});
const umountOnClose = socket.events.onClose(() => {
var _a;
actions.setConnected(false);
(_a = onCloseCallback.current) == null ? void 0 : _a.call(onCloseCallback);
});
const umountOnReconnecting = socket.events.onReconnecting((attempts) => {
var _a;
(_a = onReconnectingCallback.current) == null ? void 0 : _a.call(onReconnectingCallback, attempts);
});
const umountOnReconnectingStop = socket.events.onReconnectingStop((attempts) => {
var _a;
(_a = onReconnectingStopCallback.current) == null ? void 0 : _a.call(onReconnectingStopCallback, attempts);
});
return () => {
umountOnError();
umountOnConnecting();
umountOnOpen();
umountOnClose();
umountOnReconnecting();
umountOnReconnectingStop();
};
});
return [state.current, actions, callbacks, { setRenderKey }];
};
// src/helpers/use-socket-state/use-socket-state.constants.ts
var initialSocketState = {
data: null,
connected: false,
connecting: false,
timestamp: null
};
// src/config-provider/config-provider.tsx
import React, { useContext, useMemo, useState } from "react";
import { jsx } from "react/jsx-runtime";
var ConfigContext = React.createContext([{}, () => null]);
var ConfigProvider = ({ children, config }) => {
const [currentConfig, setConfig] = useState(config || {});
const value = useMemo(() => {
const contextValue = [currentConfig, setConfig];
return contextValue;
}, [currentConfig]);
return /* @__PURE__ */ jsx(ConfigContext.Provider, { value, children });
};
var useConfigProvider = () => {
const config = useContext(ConfigContext);
return config;
};
// src/hooks/use-fetch/use-fetch.hooks.ts
var useFetch = (request, options = useFetchDefaultOptions) => {
const [globalConfig] = useConfigProvider();
const {
dependencies = useFetchDefaultOptions.dependencies,
disabled = useFetchDefaultOptions.disabled,
dependencyTracking = useFetchDefaultOptions.dependencyTracking,
revalidate = useFetchDefaultOptions.revalidate,
initialData = useFetchDefaultOptions.initialData,
refresh = useFetchDefaultOptions.refresh,
refreshTime = useFetchDefaultOptions.refreshTime,
refetchBlurred = useFetchDefaultOptions.refetchBlurred,
refetchOnBlur = useFetchDefaultOptions.refetchOnBlur,
refetchOnFocus = useFetchDefaultOptions.refetchOnFocus,
refetchOnReconnect = useFetchDefaultOptions.refetchOnReconnect,
bounce = useFetchDefaultOptions.bounce,
bounceType = useFetchDefaultOptions.bounceType,
bounceTime = useFetchDefaultOptions.bounceTime,
bounceTimeout = useFetchDefaultOptions.bounceTime,
deepCompare = useFetchDefaultOptions.deepCompare
} = __spreadValues(__spreadValues(__spreadValues({}, useFetchDefaultOptions), globalConfig.useFetchConfig), options);
const updateKey = JSON.stringify(request.toJSON());
const requestDebounce = useDebounce({ delay: bounceTime });
const requestThrottle = useThrottle({ interval: bounceTime, timeout: bounceTimeout });
const refreshDebounce = useDebounce({ delay: refreshTime });
const { cacheKey, queueKey, client } = request;
const { cache, fetchDispatcher: dispatcher, appManager, loggerManager } = client;
const ignoreReact18DoubleRender = useRef4(true);
const logger = useRef4(loggerManager.init("useFetch")).current;
const bounceData = bounceType === "throttle" ? requestThrottle : requestDebounce;
const bounceFunction = bounceType === "throttle" ? requestThrottle.throttle : requestDebounce.debounce;
const [state, actions, { setRenderKey, setCacheData, getStaleStatus, getIsDataProcessing }] = useTrackedState({
logger,
request,
dispatcher,
initialData,
deepCompare,
dependencyTracking,
disabled,
revalidate
});
const [callbacks, listeners] = useRequestEvents({
logger,
actions,
request,
dispatcher,
setCacheData,
getIsDataProcessing
});
const { addCacheDataListener, addLifecycleListeners, clearCacheDataListener } = listeners;
const handleFetch = () => {
if (!disabled) {
logger.debug(`Fetching data`);
dispatcher.add(request);
} else {
logger.debug(`Cannot add to fetch queue`, { disabled });
}
};
function handleRefresh() {
if (!refresh) {
refreshDebounce.reset();
return;
}
refreshDebounce.debounce(() => {
const isBlurred = !appManager.isFocused;
const isFetching = dispatcher.hasRunningRequests(request.queueKey);
const isQueued = dispatcher.getIsActiveQueue(request.queueKey);
const isActive = isFetching || isQueued;
const canRefreshBlurred = isBlurred && refetchBlurred && !isActive;
const canRefreshFocused = !isBlurred && !isActive;
if (canRefreshBlurred || canRefreshFocused) {
handleFetch();
logger.debug(`Performing refresh request`);
}
handleRefresh();
});
}
const handleInvalidation = (invalidateKey) => {
if (invalidateKey && invalidateKey instanceof Request) {
cache.invalidate(getRequestKey(invalidateKey));
} else if (invalidateKey && !(invalidateKey instanceof Request)) {
cache.invalidate(invalidateKey);
}
};
const refetch = (invalidateKey) => {
if (invalidateKey && Array.isArray(invalidateKey)) {
invalidateKey.forEach(handleInvalidation);
} else if (invalidateKey && !Array.isArray(invalidateKey)) {
handleInvalidation(invalidateKey);
} else {
handleFetch();
handleRefresh();
}
};
const getIsFetchingIdentity = () => {
return dispatcher.getRunningRequests(queueKey).some((running) => running.request.cacheKey === cacheKey);
};
const initialFetchData = () => {
const hasStaleData = getStaleStatus();
const isFetching = getIsFetchingIdentity();
if ((revalidate || hasStaleData) && !isFetching) {
handleFetch();
}
};
const updateFetchData = () => {
const hasStaleData = getStaleStatus();
const shouldUpdate = !revalidate ? hasStaleData : true;
if (!ignoreReact18DoubleRender.current && shouldUpdate) {
if (bounce) {
logger.debug(`Bounce request with ${bounceType}`, { queueKey, request });
bounceFunction(() => handleFetch());
} else {
handleFetch();
}
} else {
ignoreReact18DoubleRender.current = false;
}
};
const handleMountEvents = () => {
addCacheDataListener(request);
addLifecycleListeners(request);
const focusUnmount = appManager.events.onFocus(() => {
if (refetchOnFocus) {
handleFetch();
handleRefresh();
}
});
const blurUnmount = appManager.events.onBlur(() => {
if (refetchOnBlur) {
handleFetch();
handleRefresh();
}
});
const onlineUnmount = appManager.events.onOnline(() => {
if (refetchOnReconnect) {
handleFetch();
handleRefresh();
}
});
const invalidateUnmount = cache.events.onInvalidate(cacheKey, handleFetch);
const unmount = () => {
clearCacheDataListener();
focusUnmount();
blurUnmount();
onlineUnmount();
invalidateUnmount();
};
return unmount;
};
useDidUpdate3(handleMountEvents, [updateKey], true);
useDidMount2(initialFetchData);
useDidUpdate3(updateFetchData, [updateKey, disabled, ...dependencies], true);
useDidUpdate3(handleRefresh, [updateKey, ...dependencies, disabled, refresh, refreshTime], true);
useWillUnmount2(() => {
ignoreReact18DoubleRender.current = true;
});
return __spreadProps(__spreadValues(__spreadValues({
get data() {
setRenderKey("data");
return state.data;
},
get error() {
setRenderKey("error");
return state.error;
},
get loading() {
setRenderKey("loading");
return state.loading;
},
get status() {
setRenderKey("status");
return state.status;
},
get success() {
setRenderKey("success");
return state.success;
},
get extra() {
setRenderKey("extra");
return state.extra;
},
get retries() {
setRenderKey("retries");
return state.retries;
},
get timestamp() {
setRenderKey("timestamp");
return state.timestamp;
},
bounce: getBounceData(bounceData)
}, actions), callbacks), {
refetch
});
};
// src/hooks/use-fetch/use-fetch.utils.ts
var getRefreshTime = (refreshTime, dataTimestamp) => {
if (dataTimestamp) {
const timeDiff = Date.now() - +dataTimestamp;
return timeDiff < refreshTime ? refreshTime - timeDiff : refreshTime;
}
return refreshTime;
};
// src/hooks/use-fetch/use-fetch.constants.ts
import { DateInterval } from "@hyper-fetch/core";
var useFetchDefaultOptions = {
dependencies: [],
disabled: false,
dependencyTracking: true,
revalidate: true,
initialData: null,
refresh: false,
refreshTime: DateInterval.hour,
refetchBlurred: true,
refetchOnBlur: false,
refetchOnFocus: false,
refetchOnReconnect: false,
bounce: false,
bounceType: "debounce",
bounceTime: 400,
deepCompare: true
};
// src/hooks/use-submit/use-submit.hooks.ts
import { useMemo as useMemo2, useRef as useRef5 } from "react";
import {
Request as Request2,
getRequestKey as getRequestKey2,
sendRequest
} from "@hyper-fetch/core";
import { useDidMount as useDidMount3 } from "@better-hooks/lifecycle";
import { useDebounce as useDebounce2, useThrottle as useThrottle2 } from "@better-hooks/performance";
var useSubmit = (request, options = useSubmitDefaultOptions) => {
const [globalConfig] = useConfigProvider();
const mergedOptions = useMemo2(
() => __spreadValues(__spreadValues(__spreadValues({}, useSubmitDefaultOptions), globalConfig.useSubmitConfig), options),
[globalConfig.useSubmitConfig, JSON.stringify(options), options.deepCompare]
);
const { disabled, dependencyTracking, initialData, bounce, bounceType, bounceTime, deepCompare } = mergedOptions;
const { client } = request;
const { cache, submitDispatcher: dispatcher, loggerManager } = client;
const logger = useRef5(loggerManager.init("useSubmit")).current;
const requestDebounce = useDebounce2({ delay: bounceTime });
const requestThrottle = useThrottle2({
interval: bounceTime,
timeout: "bounceTimeout" in mergedOptions ? mergedOptions.bounceTimeout : bounceTime
});
const bounceResolver = useRef5(() => null);
const bounceData = bounceType === "throttle" ? requestThrottle : requestDebounce;
const bounceFunction = bounceType === "throttle" ? requestThrottle.throttle : requestDebounce.debounce;
const [state, actions, { setRenderKey, setCacheData, getIsDataProcessing }] = useTrackedState({
logger,
request,
dispatcher,
initialData,
deepCompare,
dependencyTracking
});
const [callbacks, listeners] = useRequestEvents({
logger,
actions,
request,
dispatcher,
setCacheData,
getIsDataProcessing
});
const { addCacheDataListener, addLifecycleListeners } = listeners;
const handleSubmit = (submitOptions) => {
const requestClone = request.clone(submitOptions);
if (disabled) {
logger.warning(`Cannot submit request`, { disabled, submitOptions });
return Promise.resolve({
data: null,
error: new Error("Cannot submit request. Option 'disabled' is enabled"),
status: null,
extra: request.client.defaultExtra
});
}
const triggerRequest = () => {
addCacheDataListener(requestClone);
return sendRequest(requestClone, __spreadProps(__spreadValues({
dispatcherType: "submit"
}, submitOptions), {
onSettle: (requestId, cmd) => {
var _a;
addLifecycleListeners(requestClone, requestId);
(_a = submitOptions == null ? void 0 : submitOptions.onSettle) == null ? void 0 : _a.call(submitOptions, requestId, cmd);
}
}));
};
return new Promise((resolve) => {
const performSubmit = () => __async(void 0, null, function* () {
logger.debug(`Submitting request`, { disabled, submitOptions });
if (bounce) {
const bouncedResolve = bounceResolver.current;
bounceResolver.current = (value) => {
bouncedResolve(value);
resolve(value);
};
bounceFunction(() => __async(void 0, null, function* () {
const callback = bounceResolver.current;
bounceResolver.current = () => null;
const value = yield triggerRequest();
callback(value);
}));
} else {
const value = yield triggerRequest();
resolve(value);
}
});
performSubmit();
});
};
const handleInvalidation = (invalidateKey) => {
if (invalidateKey && invalidateKey instanceof Request2) {
cache.invalidate(getRequestKey2(invalidateKey));
} else if (invalidateKey && !(invalidateKey instanceof Request2)) {
cache.invalidate(invalidateKey);
}
};
const refetch = (invalidateKey) => {
if (!invalidateKey)
return;
if (invalidateKey && Array.isArray(invalidateKey)) {
invalidateKey.forEach(handleInvalidation);
} else if (invalidateKey && !Array.isArray(invalidateKey)) {
handleInvalidation(invalidateKey);
}
};
const handlers = {
onSubmitSuccess: callbacks.onSuccess,
onSubmitError: callbacks.onError,
onSubmitFinished: callbacks.onFinished,
onSubmitRequestStart: callbacks.onRequestStart,
onSubmitResponseStart: callbacks.onResponseStart,
onSubmitDownloadProgress: callbacks.onDownloadProgress,
onSubmitUploadProgress: callbacks.onUploadProgress,
onSubmitOfflineError: callbacks.onOfflineError,
onSubmitAbort: callbacks.onAbort
};
useDidMount3(() => {
addCacheDataListener(request);
});
return __spreadProps(__spreadValues(__spreadValues({
submit: handleSubmit,
get data() {
setRenderKey("data");
return state.data;
},
get error() {
setRenderKey("error");
return state.error;
},
get submitting() {
setRenderKey("loading");
return state.loading;
},
get status() {
setRenderKey("status");
return state.status;
},
get success() {
setRenderKey("success");
return state.success;
},
get extra() {
setRenderKey("extra");
return state.extra;
},
get retries() {
setRenderKey("retries");
return state.retries;
},
get timestamp() {
setRenderKey("timestamp");
return state.timestamp;
},
abort: callbacks.abort
}, actions), handlers), {
bounce: getBounceData(bounceData),
refetch
});
};
// src/hooks/use-submit/use-submit.constants.ts
var useSubmitDefaultOptions = {
disabled: false,
dependencyTracking: true,
initialData: null,
bounce: false,
bounceType: "debounce",
bounceTime: 400,
deepCompare: true
};
// src/hooks/use-queue/use-queue.hooks.ts
import { useState as useState2, useRef as useRef6 } from "react";
import { getRequestDispatcher } from "@hyper-fetch/core";
import { useDidMount as useDidMount4, useDidUpdate as useDidUpdate4 } from "@better-hooks/lifecycle";
var useQueue = (request, options = useQueueDefaultOptions) => {
const [globalConfig] = useConfigProvider();
const { queueType = "auto" } = __spreadValues(__spreadValues(__spreadValues({}, useQueueDefaultOptions), globalConfig.useQueueConfig), options);
const { abortKey, queueKey, client } = request;
const { requestManager } = client;
const [dispatcher] = getRequestDispatcher(request, queueType);
const unmountCallbacks = useRef6(null);
const [stopped, setStopped] = useState2(false);
const [requests, setRequests] = useState2([]);
const createRequestsArray = (queueElements) => {
return queueElements.map((req) => __spreadProps(__spreadValues({}, req), {
stopRequest: () => dispatcher.stopRequest(queueKey, req.requestId),
startRequest: () => dispatcher.startRequest(queueKey, req.requestId),
deleteRequest: () => dispatcher.delete(queueKey, req.requestId, abortKey)
}));
};
const mergePayloadType = (requestId, data) => {
setRequests((prev) => prev.map((el) => el.requestId === requestId ? __spreadValues(__spreadValues({}, el), data) : el));
};
const getInitialState2 = () => {
const requestQueue = dispatcher.getQueue(queueKey);
setStopped(requestQueue.stopped);
setRequests(createRequestsArray(requestQueue.requests));
};
const updateQueueState = (values) => {
setStopped(values.stopped);
setRequests(createRequestsArray(values.requests));
};
const mountEvents = () => {
var _a;
const unmountChange = dispatcher.events.onQueueChange(queueKey, updateQueueState);
const unmountStatus = dispatcher.events.onQueueStatus(queueKey, updateQueueState);
const unmountDownload = requestManager.events.onDownloadProgress(queueKey, (progress, { requestId }) => {
mergePayloadType(requestId, { downloading: progress });
});
const unmountUpload = requestManager.events.onUploadProgress(queueKey, (progress, { requestId }) => {
mergePayloadType(requestId, { uploading: progress });
});
const unmount = () => {
unmountStatus();
unmountChange();
unmountDownload();
unmountUpload();
};
(_a = unmountCallbacks.current) == null ? void 0 : _a.call(unmountCallbacks);
unmountCallbacks.current = unmount;
return unmount;
};
useDidMount4(getInitialState2);
useDidUpdate4(mountEvents, [stopped, requests, setRequests, setStopped], true);
return {
stopped,
requests,
stop: () => dispatcher.stop(queueKey),
pause: () => dispatcher.pause(queueKey),
start: () => dispatcher.start(queueKey)
};
};
// src/hooks/use-queue/use-queue.constants.ts
var useQueueDefaultOptions = {
queueType: "auto"
};
// src/hooks/use-cache/use-cache.hooks.ts
import { useRef as useRef7 } from "react";
import { useDidUpdate as useDidUpdate5 } from "@better-hooks/lifecycle";
import { getRequestDispatcher as getRequestDispatcher2, Request as Request3, getRequestKey as getRequestKey3 } from "@hyper-fetch/core";
var useCache = (request, options = useCacheDefaultOptions) => {
const { cacheKey, client } = request;
const { cache, loggerManager } = client;
const logger = useRef7(loggerManager.init("useCache")).current;
const [dispatcher] = getRequestDispatcher2(request);
const updateKey = JSON.stringify(request.toJSON());
const [globalConfig] = useConfigProvider();
const { dependencyTracking, initialData, deepCompare } = __spreadValues(__spreadValues(__spreadValues({}, useCacheDefaultOptions), globalConfig.useCacheConfig), options);
const [state, actions, { setRenderKey, setCacheData, getIsDataProcessing }] = useTrackedState({
logger,
request,
dispatcher,
initialData,
deepCompare,
dependencyTracking
});
const [callbacks, listeners] = useRequestEvents({
logger,
actions,
request,
dispatcher,
setCacheData,
getIsDataProcessing
});
const { addCacheDataListener, addLifecycleListeners } = listeners;
const handleMountEvents = () => {
addCacheDataListener(request);
addLifecycleListeners(request);
};
useDidUpdate5(handleMountEvents, [updateKey], true);
const refetch = (invalidateKey) => {
if (invalidateKey instanceof Request3) {
cache.invalidate(getRequestKey3(invalidateKey, true));
} else if (invalidateKey) {
cache.invalidate(invalidateKey);
} else {
cache.invalidate(cacheKey);
}
};
return __spreadProps(__spreadValues({
get data() {
setRenderKey("data");
return state.data;
},
get error() {
setRenderKey("error");
return state.error;
},
get loading() {
setRenderKey("loading");
return state.loading;
},
get status() {
setRenderKey("status");
return state.status;
},
get success() {
setRenderKey("success");
return state.success;
},
get extra() {
setRenderKey("extra");
return state.extra;
},
get retries() {
setRenderKey("retries");
return state.retries;
},
get timestamp() {
setRenderKey("timestamp");
return state.timestamp;
},
onCacheError: callbacks.onError,
onCacheSuccess: callbacks.onSuccess,
onCacheChange: callbacks.onFinished
}, actions), {
refetch
});
};
// src/hooks/use-cache/use-cache.constants.ts
var useCacheDefaultOptions = {
dependencyTracking: true,
initialData: null,
deepCompare: true
};
// src/hooks/use-listener/use-listener.hooks.ts
import { useRef as useRef8 } from "react";
import { useDidUpdate as useDidUpdate6, useWillUnmount as useWillUnmount3 } from "@better-hooks/lifecycle";
var useListener = (listener, options) => {
const [globalConfig] = useConfigProvider();
const { dependencyTracking } = __spreadValues(__spreadValues({}, globalConfig.useListener), options);
const [state, actions, callbacks, { setRenderKey }] = useSocketState(listener.socket, { dependencyTracking });
const removeListenerRef = useRef8(null);
const onEventCallback = useRef8(null);
const stopListener = () => {
var _a;
(_a = removeListenerRef.current) == null ? void 0 : _a.call(removeListenerRef);
};
const listen = () => {
stopListener();
removeListenerRef.current = listener.listen({
callback: ({ data, extra }) => {
var _a;
(_a = onEventCallback.current) == null ? void 0 : _a.call(onEventCallback, { data, extra });
actions.setData(data);
actions.setTimestamp(+new Date());
}
});
};
const additionalCallbacks = {
onEvent: (callback) => {
onEventCallback.current = callback;
}
};
useDidUpdate6(
() => {
listen();
},
[listener.params, JSON.stringify(listener.options)],
true
);
useWillUnmount3(() => {
stopListener();
});
return __spreadProps(__spreadValues(__spreadValues(__spreadValues({
get data() {
setRenderKey("data");
return state.data;
},
get connected() {
setRenderKey("connected");
return state.connected;
},
get connecting() {
setRenderKey("connecting");
return state.connecting;
},
get timestamp() {
setRenderKey("timestamp");
return state.timestamp;
}
}, actions), callbacks), additionalCallbacks), {
listen
});
};
// src/hooks/use-emitter/use-emitter.hooks.ts
import { useRef as useRef9 } from "react";
var useEmitter = (emitter, options) => {
const [globalConfig] = useConfigProvider();
const { dependencyTracking } = __spreadValues(__spreadValues({}, globalConfig.useEmitter), options);
const onEventCallback = useRef9(null);
const [state, actions, callbacks, { setRenderKey }] = useSocketState(emitter.socket, { dependencyTracking });
const additionalCallbacks = {
onEvent: (callback) => {
onEventCallback.current = callback;
}
};
const emit = (emitOptions) => {
var _a;
actions.setTimestamp(+new Date());
(_a = onEventCallback.current) == null ? void 0 : _a.call(onEventCallback, emitter);
return emitter.emit(emitOptions);
};
return __spreadProps(__spreadValues(__spreadValues(__spreadValues({
get connected() {
setRenderKey("connected");
return state.connected;
},
get connecting() {
setRenderKey("connecting");
return state.connecting;
},
get timestamp() {
setRenderKey("timestamp");
return state.timestamp;
}
}, actions), callbacks), additionalCallbacks), {
emit,
reconnect: emitter.socket.reconnect
});
};
// src/hooks/use-event-messages/use-event-messages.hooks.ts
import { useRef as useRef10 } from "react";
import { useDidUpdate as useDidUpdate7 } from "@better-hooks/lifecycle";
var useEventMessages = (socket, options) => {
const [globalConfig] = useConfigProvider();
const { dependencyTracking = false, filter } = __spreadValues(__spreadValues({}, globalConfig.useEventMessages), options);
const onEventCallback = useRef10(null);
const [state, actions, callbacks, { setRenderKey }] = useSocketState(socket, { dependencyTracking });
useDidUpdate7(
() => {
const unmountListener = socket.events.onListenerEvent(({ endpoint, data, extra }) => {
var _a;
const filterFn = typeof filter === "function" ? () => filter(endpoint, data) : () => filter.includes(endpoint);
const isFiltered = filter ?