UNPKG

@hyper-fetch/react

Version:

React hooks and utils for the hyper-fetch

1,391 lines (1,369 loc) 55.3 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; 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 __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 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/index.ts var src_exports = {}; __export(src_exports, { ConfigProvider: () => ConfigProvider, getBounceData: () => getBounceData, getDetailsState: () => getDetailsState, getInitialState: () => getInitialState, getIsInitiallyLoading: () => getIsInitiallyLoading, getRefreshTime: () => getRefreshTime, getTimestamp: () => getTimestamp, getValidCacheData: () => getValidCacheData, initialSocketState: () => initialSocketState, initialState: () => initialState, isEmpty: () => isEmpty, isEqual: () => isEqual, isStaleCacheData: () => isStaleCacheData, useAppManager: () => useAppManager, useCache: () => useCache, useCacheDefaultOptions: () => useCacheDefaultOptions, useConfigProvider: () => useConfigProvider, useEmitter: () => useEmitter, useEventMessages: () => useEventMessages, useFetch: () => useFetch, useFetchDefaultOptions: () => useFetchDefaultOptions, useListener: () => useListener, useQueue: () => useQueue, useQueueDefaultOptions: () => useQueueDefaultOptions, useRequestEvents: () => useRequestEvents, useSocketState: () => useSocketState, useSubmit: () => useSubmit, useSubmitDefaultOptions: () => useSubmitDefaultOptions, useTrackedState: () => useTrackedState }); module.exports = __toCommonJS(src_exports); // src/hooks/use-fetch/use-fetch.hooks.ts var import_react5 = require("react"); var import_lifecycle4 = require("@better-hooks/lifecycle"); var import_performance = require("@better-hooks/performance"); var import_core = require("@hyper-fetch/core"); // src/helpers/use-request-events/use-request-events.hooks.ts var import_react = require("react"); var import_lifecycle = require("@better-hooks/lifecycle"); var useRequestEvents = ({ request, dispatcher, logger, actions, setCacheData, getIsDataProcessing }) => { const { responseMapper } = request; const { cache, requestManager } = request.client; const onSuccessCallback = (0, import_react.useRef)(null); const onErrorCallback = (0, import_react.useRef)(null); const onAbortCallback = (0, import_react.useRef)(null); const onOfflineErrorCallback = (0, import_react.useRef)(null); const onFinishedCallback = (0, import_react.useRef)(null); const onRequestStartCallback = (0, import_react.useRef)(null); const onResponseStartCallback = (0, import_react.useRef)(null); const onDownloadProgressCallback = (0, import_react.useRef)(null); const onUploadProgressCallback = (0, import_react.useRef)(null); const lifecycleEvents = (0, import_react.useRef)(/* @__PURE__ */ new Map()); const dataEvents = (0, import_react.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); } }); }; (0, import_lifecycle.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 var import_react2 = require("react"); var import_lifecycle2 = require("@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 = (0, import_lifecycle2.useForceUpdate)(); const state = (0, import_react2.useRef)( getInitialState({ initialResponse: initialData, dispatcher, request, disabled }) ); const renderKeys = (0, import_react2.useRef)([]); const isProcessingData = (0, import_react2.useRef)(""); 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); } }; (0, import_lifecycle2.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 ); (0, import_lifecycle2.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 var import_react3 = require("react"); var import_lifecycle3 = require("@better-hooks/lifecycle"); var useSocketState = (socket, { dependencyTracking }) => { const forceUpdate = (0, import_lifecycle3.useForceUpdate)(); const onOpenCallback = (0, import_react3.useRef)(null); const onCloseCallback = (0, import_react3.useRef)(null); const onErrorCallback = (0, import_react3.useRef)(null); const onConnectingCallback = (0, import_react3.useRef)(null); const onReconnectingCallback = (0, import_react3.useRef)(null); const onReconnectingStopCallback = (0, import_react3.useRef)(null); const state = (0, import_react3.useRef)(initialSocketState); const renderKeys = (0, import_react3.useRef)([]); 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); } }; (0, import_lifecycle3.useDidUpdate)( () => { 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; } }; (0, import_lifecycle3.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 var import_react4 = __toESM(require("react")); var import_jsx_runtime = require("react/jsx-runtime"); var ConfigContext = import_react4.default.createContext([{}, () => null]); var ConfigProvider = ({ children, config }) => { const [currentConfig, setConfig] = (0, import_react4.useState)(config || {}); const value = (0, import_react4.useMemo)(() => { const contextValue = [currentConfig, setConfig]; return contextValue; }, [currentConfig]); return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfigContext.Provider, { value, children }); }; var useConfigProvider = () => { const config = (0, import_react4.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 = (0, import_performance.useDebounce)({ delay: bounceTime }); const requestThrottle = (0, import_performance.useThrottle)({ interval: bounceTime, timeout: bounceTimeout }); const refreshDebounce = (0, import_performance.useDebounce)({ delay: refreshTime }); const { cacheKey, queueKey, client } = request; const { cache, fetchDispatcher: dispatcher, appManager, loggerManager } = client; const ignoreReact18DoubleRender = (0, import_react5.useRef)(true); const logger = (0, import_react5.useRef)(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 import_core.Request) { cache.invalidate((0, import_core.getRequestKey)(invalidateKey)); } else if (invalidateKey && !(invalidateKey instanceof import_core.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; }; (0, import_lifecycle4.useDidUpdate)(handleMountEvents, [updateKey], true); (0, import_lifecycle4.useDidMount)(initialFetchData); (0, import_lifecycle4.useDidUpdate)(updateFetchData, [updateKey, disabled, ...dependencies], true); (0, import_lifecycle4.useDidUpdate)(handleRefresh, [updateKey, ...dependencies, disabled, refresh, refreshTime], true); (0, import_lifecycle4.useWillUnmount)(() => { 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 var import_core2 = require("@hyper-fetch/core"); var useFetchDefaultOptions = { dependencies: [], disabled: false, dependencyTracking: true, revalidate: true, initialData: null, refresh: false, refreshTime: import_core2.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 var import_react6 = require("react"); var import_core3 = require("@hyper-fetch/core"); var import_lifecycle5 = require("@better-hooks/lifecycle"); var import_performance2 = require("@better-hooks/performance"); var useSubmit = (request, options = useSubmitDefaultOptions) => { const [globalConfig] = useConfigProvider(); const mergedOptions = (0, import_react6.useMemo)( () => __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 = (0, import_react6.useRef)(loggerManager.init("useSubmit")).current; const requestDebounce = (0, import_performance2.useDebounce)({ delay: bounceTime }); const requestThrottle = (0, import_performance2.useThrottle)({ interval: bounceTime, timeout: "bounceTimeout" in mergedOptions ? mergedOptions.bounceTimeout : bounceTime }); const bounceResolver = (0, import_react6.useRef)(() => 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 (0, import_core3.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 import_core3.Request) { cache.invalidate((0, import_core3.getRequestKey)(invalidateKey)); } else if (invalidateKey && !(invalidateKey instanceof import_core3.Request)) { 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 }; (0, import_lifecycle5.useDidMount)(() => { 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 var import_react7 = require("react"); var import_core4 = require("@hyper-fetch/core"); var import_lifecycle6 = require("@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] = (0, import_core4.getRequestDispatcher)(request, queueType); const unmountCallbacks = (0, import_react7.useRef)(null); const [stopped, setStopped] = (0, import_react7.useState)(false); const [requests, setRequests] = (0, import_react7.useState)([]); 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; }; (0, import_lifecycle6.useDidMount)(getInitialState2); (0, import_lifecycle6.useDidUpdate)(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 var import_react8 = require("react"); var import_lifecycle7 = require("@better-hooks/lifecycle"); var import_core5 = require("@hyper-fetch/core"); var useCache = (request, options = useCacheDefaultOptions) => { const { cacheKey, client } = request; const { cache, loggerManager } = client; const logger = (0, import_react8.useRef)(loggerManager.init("useCache")).current; const [dispatcher] = (0, import_core5.getRequestDispatcher)(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); }; (0, import_lifecycle7.useDidUpdate)(handleMountEvents, [updateKey], true); const refetch = (invalidateKey) => { if (invalidateKey instanceof import_core5.Request) { cache.invalidate((0, import_core5.getRequestKey)(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 var import_react9 = require("react"); var import_lifecycle8 = require("@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 = (0, import_react9.useRef)(null); const onEventCallback = (0, import_react9.useRef)(null); const stopListener = () => { var _a; (_a = removeListenerRef.current) == null ? void 0 : _a.call(removeListenerRef); }; const listen = () => { stopListener(); removeListenerRef.current = listener.listen({ ca