diff --git a/package.json b/package.json index b7bef44..a73a829 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-react", - "version": "3.7.7", + "version": "3.7.8", "description": "React hooks for data fetching", "main": "dist/index.js", "scripts": { diff --git a/src/components/index.tsx b/src/components/index.tsx index b5d2190..6221546 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -35,7 +35,7 @@ export function SSRSuspense({ // This will render the fallback in the server return ( ssr ? fallback : {children} - ) as JSX.Element + ) as React.JSX.Element } export function FetchConfig(props: FetchContextType) { diff --git a/src/hooks/others.ts b/src/hooks/others.ts index 269d0da..9e1b950 100644 --- a/src/hooks/others.ts +++ b/src/hooks/others.ts @@ -221,6 +221,7 @@ export function useSuccess(id: any) { } /** + * @deprecated - Use the useFetch hook instead * Get everything from a `useFetch` call using its id */ export function useFetchId(id: any) { diff --git a/src/hooks/use-fetch.ts b/src/hooks/use-fetch.ts index c7fe131..5f00972 100644 --- a/src/hooks/use-fetch.ts +++ b/src/hooks/use-fetch.ts @@ -1,5 +1,5 @@ -"use client"; -import { useState, useEffect, useMemo, useRef, useCallback } from "react"; +'use client' +import { useState, useEffect, useMemo, useRef, useCallback } from 'react' import { abortControllers, @@ -29,10 +29,10 @@ import { suspenseRevalidationStarted, onlineHandled, offlineHandled, - hasData, -} from "../internal"; + hasData +} from '../internal' -import { DEFAULT_RESOLVER, METHODS } from "../internal/constants"; +import { DEFAULT_RESOLVER, METHODS } from '../internal/constants' import { CustomResponse, @@ -41,16 +41,16 @@ import { FetchContextType, HTTP_METHODS, ImperativeFetch, - TimeSpan, -} from "../types"; + TimeSpan +} from '../types' import { createImperativeFetch, getMiliseconds, getTimePassed, revalidate, - useIsomorphicLayoutEffect, -} from "../utils"; + useIsomorphicLayoutEffect +} from '../utils' import { createRequestFn, getRequestHeaders, @@ -63,21 +63,21 @@ import { queue, serialize, setURLParams, - windowExists, -} from "../utils/shared"; -import { $context } from "../internal/shared"; + windowExists +} from '../utils/shared' +import { $context } from '../internal/shared' /** * Passing `undefined` to `new Date()` returns `Invalid Date {}`, so return null instead */ const getDateIfValid = (d: Date | null) => // @ts-ignore - Evals to a Date - (d?.toString() === "Invalid Date" || d === null ? null : d) as Date; + (d?.toString() === 'Invalid Date' || d === null ? null : d) as Date /** * Termporary form data is set with the submit method in useFetch and is deleted immediately after resolving (see line #858) * */ -const temporaryFormData = new Map(); +const temporaryFormData = new Map() /** * Fetch hook @@ -86,34 +86,35 @@ export function useFetch( init: FetchConfigType | string | Request, options?: FetchConfigTypeNoUrl ) { - const $ctx = useHRFContext(); + const $ctx = useHRFContext() const ctx: FetchContextType = { ...$context.value, ...$ctx, query: { ...$context?.value?.query, - ...$ctx?.query, + ...$ctx?.query }, headers: { ...$context.value?.headers, - ...$ctx?.headers, - }, - }; + ...$ctx?.headers + } + } - const valueMap = new Map(Object.entries(ctx.value ?? {})); + const valueMap = new Map(Object.entries(ctx.value ?? {})) - const formRef = useRef(null); + const formRef = useRef(null) // @ts-ignore - const isRequest = init instanceof Object && init?.json; + const isRequest = init instanceof Object && init?.json const optionsConfig = - typeof init === "string" + typeof init === 'string' ? { // Pass init as the url if init is a string url: init, ...options, + id: options?.id ?? options?.key } : isRequest ? { @@ -121,8 +122,14 @@ export function useFetch( method: init.method, init, ...options, + id: options?.id ?? options?.key } - : ({ ...init, ...options } as FetchConfigType); + : ({ + ...init, + ...options, + // @ts-expect-error + id: init?.id ?? init?.key + } as FetchConfigType) const { onOnline = ctx.onOnline, @@ -136,7 +143,7 @@ export function useFetch( method = isRequest ? init.method : (METHODS.GET as HTTP_METHODS), headers = {} as Headers, body = undefined as unknown as Body, - formatBody = (e) => JSON.stringify(e), + formatBody = e => JSON.stringify(e), resolver = isFunction(ctx.resolver) ? ctx.resolver : DEFAULT_RESOLVER, onError, auto = isDefined(ctx.auto) ? ctx.auto : true, @@ -155,14 +162,14 @@ export function useFetch( maxCacheAge = ctx.maxCacheAge, fetcher = ctx.fetcher, middleware = ctx.middleware, - transform = ctx.transform, - } = optionsConfig; + transform = ctx.transform + } = optionsConfig const $fetch = isFunction(fetcher) ? fetcher : windowExists ? fetch - : () => new Response(serialize(initialDataValue)); + : () => new Response(serialize(initialDataValue)) const config = { query, @@ -171,86 +178,86 @@ export function useFetch( method, headers, body, - formatBody, - }; + formatBody + } - const { cacheProvider: $cacheProvider = defaultCache } = ctx; + const { cacheProvider: $cacheProvider = defaultCache } = ctx - const logStart = isFunction(onFetchStart); - const logEnd = isFunction(onFetchEnd); + const logStart = isFunction(onFetchStart) + const logEnd = isFunction(onFetchEnd) - const { cacheProvider = $cacheProvider } = optionsConfig; + const { cacheProvider = $cacheProvider } = optionsConfig - const requestCallId = useMemo(() => `${Math.random()}`.split(".")[1], []); + const requestCallId = useMemo(() => `${Math.random()}`.split('.')[1], []) - const willResolve = isDefined(onResolve); - const handleError = isDefined(onError); - const handleOnAbort = isDefined(onAbort); - const handleMutate = isDefined(onMutate); - const handleOnline = isDefined(onOnline); - const handleOffline = isDefined(onOffline); + const willResolve = isDefined(onResolve) + const handleError = isDefined(onError) + const handleOnAbort = isDefined(onAbort) + const handleMutate = isDefined(onMutate) + const handleOnline = isDefined(onOnline) + const handleOffline = isDefined(onOffline) const retryOnReconnect = optionsConfig.auto === false ? false : isDefined(optionsConfig.retryOnReconnect) ? optionsConfig.retryOnReconnect - : ctx.retryOnReconnect; + : ctx.retryOnReconnect const reqQuery = { ...ctx.query, - ...config.query, - }; + ...config.query + } const reqParams = { ...ctx.params, - ...config.params, - }; + ...config.params + } const rawUrl = (hasBaseUrl(url) - ? "" + ? '' : !isDefined(config.baseUrl!) ? !isDefined(ctx.baseUrl!) - ? "" + ? '' : ctx.baseUrl! - : config.baseUrl!) + url; + : config.baseUrl!) + url - const defaultId = [method, url].join(" "); + const defaultId = optionsConfig.key ?? [method, url].join(' ') - const { id = defaultId } = optionsConfig; + const { id = defaultId } = optionsConfig - const idString = serialize(id); + const idString = serialize(id) const urlWithParams = useMemo( () => setURLParams(rawUrl, reqParams), [serialize(reqParams), config.baseUrl, ctx.baseUrl, url] - ); + ) - const resolvedKey = serialize({ idString }); + const resolvedKey = serialize({ idString }) if (!statusCodes.has(resolvedKey)) { - statusCodes.set(resolvedKey, null); + statusCodes.set(resolvedKey, null) } - const resolvedDataKey = serialize({ idString, reqQuery, reqParams }); + const resolvedDataKey = serialize({ idString, reqQuery, reqParams }) - const ageKey = ["max-age", resolvedDataKey].join("-"); + const ageKey = ['max-age', resolvedDataKey].join('-') - const paginationCache = cacheProvider.get(resolvedDataKey); + const paginationCache = cacheProvider.get(resolvedDataKey) - const normalCache = cacheProvider.get(resolvedKey); + const normalCache = cacheProvider.get(resolvedKey) - const maxAge = getMiliseconds(maxCacheAge || "0 ms"); + const maxAge = getMiliseconds(maxCacheAge || '0 ms') // Revalidates if passed maxCacheAge has changed - if (!cacheProvider.get("maxAgeValue" + resolvedDataKey)) { - cacheProvider.set("maxAgeValue" + resolvedDataKey, maxCacheAge || "0 ms"); + if (!cacheProvider.get('maxAgeValue' + resolvedDataKey)) { + cacheProvider.set('maxAgeValue' + resolvedDataKey, maxCacheAge || '0 ms') } else { - if (cacheProvider.get("maxAgeValue" + resolvedDataKey) !== maxCacheAge) { - cacheProvider.set(ageKey, 0); - cacheProvider.set("maxAgeValue" + resolvedDataKey, maxCacheAge); + if (cacheProvider.get('maxAgeValue' + resolvedDataKey) !== maxCacheAge) { + cacheProvider.set(ageKey, 0) + cacheProvider.set('maxAgeValue' + resolvedDataKey, maxCacheAge) } } @@ -258,45 +265,45 @@ export function useFetch( !isDefined(cacheProvider.get(ageKey)) || !notNull(cacheProvider.get(ageKey)) ) { - cacheProvider.set(ageKey, maxAge); + cacheProvider.set(ageKey, maxAge) } - const isExpired = Date.now() > cacheProvider.get(ageKey); + const isExpired = Date.now() > cacheProvider.get(ageKey) const debounce = optionsConfig.debounce ? getMiliseconds(optionsConfig.debounce) - : 0; + : 0 - const canRevalidate = auto && isExpired; + const canRevalidate = auto && isExpired - const suspense = $suspense || willSuspend.get(resolvedKey); + const suspense = $suspense || willSuspend.get(resolvedKey) if (!suspense) { - if (url !== "") { - suspenseInitialized.set(resolvedKey, true); + if (url !== '') { + suspenseInitialized.set(resolvedKey, true) } } if (suspense && !willSuspend.get(resolvedKey)) { if (!suspenseInitialized.get(resolvedKey)) { - willSuspend.set(resolvedKey, true); + willSuspend.set(resolvedKey, true) } } const realUrl = urlWithParams + - (urlWithParams.includes("?") ? (optionsConfig?.query ? `&` : "") : "?"); + (urlWithParams.includes('?') ? (optionsConfig?.query ? `&` : '') : '?') if (!previousProps.has(resolvedKey)) { - if (url !== "") { - previousProps.set(resolvedKey, optionsConfig); + if (url !== '') { + previousProps.set(resolvedKey, optionsConfig) } } const configUrl = urls[resolvedKey] || { realUrl, - rawUrl, - }; + rawUrl + } const stringDeps = serialize( Object.assign( @@ -311,50 +318,50 @@ export function useFetch( { reqQuery }, { reqParams } ) - ); + ) // This helps pass default values to other useFetch calls using the same id useEffect(() => { if (isDefined(optionsConfig.default)) { if (!fetcherDefaults.has(resolvedKey)) { - if (url !== "") { + if (url !== '') { if (!isDefined(cacheProvider.get(resolvedDataKey))) { - fetcherDefaults.set(resolvedKey, optionsConfig.default); + fetcherDefaults.set(resolvedKey, optionsConfig.default) } } else { if (!isDefined(cacheProvider.get(resolvedDataKey))) { requestsProvider.emit(resolvedKey, { requestCallId, - data: optionsConfig.default, - }); + data: optionsConfig.default + }) } } } } else { if (fetcherDefaults.has(resolvedKey)) { if (!isDefined(cacheProvider.get(resolvedDataKey))) { - setData(fetcherDefaults.get(resolvedKey)); + setData(fetcherDefaults.get(resolvedKey)) } } } - }, [resolvedKey]); + }, [resolvedKey]) - const def = optionsConfig?.default ?? fetcherDefaults.get(resolvedKey); + const def = optionsConfig?.default ?? fetcherDefaults.get(resolvedKey) useEffect(() => { if (!canRevalidate) { - runningRequests.set(resolvedKey, false); + runningRequests.set(resolvedKey, false) } - }, []); + }, []) - const requestCache = cacheProvider.get(resolvedDataKey); + const requestCache = cacheProvider.get(resolvedDataKey) - const defaultFromContext = valueMap.get(resolvedKey); + const defaultFromContext = valueMap.get(resolvedKey) const initialDataValue = - valuesMemory.get(resolvedKey) ?? requestCache ?? defaultFromContext ?? def; + valuesMemory.get(resolvedKey) ?? requestCache ?? defaultFromContext ?? def - const hasInitialOrFallbackData = isDefined(initialDataValue); + const hasInitialOrFallbackData = isDefined(initialDataValue) const [fetchState, setFetchState] = useState({ data: initialDataValue, @@ -363,156 +370,156 @@ export function useFetch( ? isPending(resolvedKey) || (revalidateOnMount ? !jsonCompare( - JSON.parse(previousConfig.get(resolvedKey) || "{}"), + JSON.parse(previousConfig.get(resolvedKey) || '{}'), optionsConfig ) : !jsonCompare( - JSON.parse(previousConfig.get(resolvedKey) || "{}"), + JSON.parse(previousConfig.get(resolvedKey) || '{}'), optionsConfig )) : false, error: (hasErrors.get(resolvedDataKey) || false) as boolean, - completedAttempts: 0, - }); + completedAttempts: 0 + }) const thisDeps = useRef({ data: false, online: false, loading: false, error: false, - completedAttempts: false, - }).current; + completedAttempts: false + }).current const inDeps = (k: keyof typeof thisDeps) => { - return thisDeps[k]; - }; + return thisDeps[k] + } - const { data, loading, online, error, completedAttempts } = fetchState; + const { data, loading, online, error, completedAttempts } = fetchState - const isLoading = isExpired ? isPending(resolvedKey) || loading : false; + const isLoading = isExpired ? isPending(resolvedKey) || loading : false const loadingFirst = - !(hasData.get(resolvedDataKey) || hasData.get(resolvedKey)) && isLoading; + !(hasData.get(resolvedDataKey) || hasData.get(resolvedKey)) && isLoading if (!isExpired) { if (error) { - setError(false); + setError(false) } } function setData(v: any) { - setFetchState((p) => { + setFetchState(p => { if (isFunction(v)) { - const newVal = v(p.data); + const newVal = v(p.data) if (!jsonCompare(p.data, newVal)) { return { ...p, - data: newVal, - }; + data: newVal + } } } else { if (!jsonCompare(p.data, v)) { return { ...p, - data: v, - }; + data: v + } } } - return p; - }); + return p + }) } - const thisCache = paginationCache ?? normalCache ?? data ?? def ?? null; + const thisCache = paginationCache ?? normalCache ?? data ?? def ?? null // Used JSON as deppendency instead of directly using a reference to data - const rawJSON = serialize(data); + const rawJSON = serialize(data) function setOnline(v: any) { - setFetchState((p) => { + setFetchState(p => { if (online !== p.online) { return { ...p, - online: v, - }; + online: v + } } - return p; - }); + return p + }) } const requestHeaders = { ...ctx.headers, - ...config.headers, - }; + ...config.headers + } function setError(v: any) { - setFetchState((p) => { + setFetchState(p => { if (isFunction(v)) { - const newErroValue = v(p.error); + const newErroValue = v(p.error) if (newErroValue !== p.error) { return { ...p, - error: newErroValue, - }; + error: newErroValue + } } } else { if (v !== p.error) { return { ...p, - error: v, - }; + error: v + } } } - return p; - }); + return p + }) } function setLoading(v: any) { - setFetchState((p) => { + setFetchState(p => { if (isFunction(v)) { - const newLoadingValue = v(p.loading); + const newLoadingValue = v(p.loading) if (newLoadingValue !== p.loading) { return { ...p, - loading: newLoadingValue, - }; + loading: newLoadingValue + } } } else { if (v !== p.loading) { return { ...p, - loading: v, - }; + loading: v + } } } - return p; - }); + return p + }) } function setCompletedAttempts(v: any) { - setFetchState((p) => { + setFetchState(p => { if (isFunction(v)) { - const newCompletedAttempts = v(p.completedAttempts); + const newCompletedAttempts = v(p.completedAttempts) if (newCompletedAttempts !== p.completedAttempts) { return { ...p, - completedAttempts: newCompletedAttempts, - }; + completedAttempts: newCompletedAttempts + } } } else { if (v !== p.completedAttempts) { return { ...p, - completedAttempts: v, - }; + completedAttempts: v + } } } - return p; - }); + return p + }) } const requestAbortController: AbortController = - abortControllers.get(resolvedKey) ?? new AbortController(); + abortControllers.get(resolvedKey) ?? new AbortController() - const isGqlRequest = isDefined((optionsConfig as any)["__gql"]); + const isGqlRequest = isDefined((optionsConfig as any)['__gql']) const fetchData = useCallback( async function fetchData( @@ -520,78 +527,78 @@ export function useFetch( ) { const rawUrl = (hasBaseUrl(url) - ? "" + ? '' : !isDefined(config.baseUrl!) ? !isDefined(ctx.baseUrl!) - ? "" + ? '' : ctx.baseUrl! - : config.baseUrl!) + url; + : config.baseUrl!) + url - const urlWithParams = setURLParams(rawUrl, c.params); + const urlWithParams = setURLParams(rawUrl, c.params) const realUrl = urlWithParams + - (urlWithParams.includes("?") ? (c?.query !== "" ? `&` : "") : ""); + (urlWithParams.includes('?') ? (c?.query !== '' ? `&` : '') : '') if ( !jsonCompare( - JSON.parse(previousConfig.get(resolvedKey) || "{}"), + JSON.parse(previousConfig.get(resolvedKey) || '{}'), optionsConfig ) ) { - previousProps.set(resolvedKey, optionsConfig); + previousProps.set(resolvedKey, optionsConfig) queue(() => { - if (url !== "") { + if (url !== '') { const newUrls = { realUrl, - rawUrl, - }; + rawUrl + } - urls[resolvedKey] = newUrls; + urls[resolvedKey] = newUrls } - }); + }) if (!isPending(resolvedKey)) { - runningRequests.set(resolvedKey, auto); - hasErrors.set(resolvedDataKey, false); - hasErrors.set(resolvedKey, false); + runningRequests.set(resolvedKey, auto) + hasErrors.set(resolvedDataKey, false) + hasErrors.set(resolvedKey, false) - resolvedOnErrorCalls.set(resolvedKey, false); - resolvedHookCalls.set(resolvedKey, false); + resolvedOnErrorCalls.set(resolvedKey, false) + resolvedHookCalls.set(resolvedKey, false) - previousConfig.set(resolvedKey, serialize(optionsConfig)); + previousConfig.set(resolvedKey, serialize(optionsConfig)) - let newAbortController = new AbortController(); + let newAbortController = new AbortController() - cacheProvider.set(ageKey, Date.now() - 1); + cacheProvider.set(ageKey, Date.now() - 1) requestsProvider.emit(resolvedKey, { requestCallId: loadingFirst ? requestCallId : undefined, loading: true, requestAbortController: newAbortController, - error: false, - }); + error: false + }) - abortControllers.set(resolvedKey, newAbortController); + abortControllers.set(resolvedKey, newAbortController) - let $$data: any; + let $$data: any - let rpc: any = {}; + let rpc: any = {} try { - let reqConfig = {}; + let reqConfig = {} // @ts-ignore - let _headers = isRequest ? getRequestHeaders(init) : {}; + let _headers = isRequest ? getRequestHeaders(init) : {} if (isRequest) { for (let k in init) { // @ts-ignore Getting keys from Request init - reqConfig[k] = init[k]; + reqConfig[k] = init[k] } } - cacheProvider.set("requestStart" + resolvedDataKey, Date.now()); - requestInitialTimes.set(resolvedDataKey, Date.now()); + cacheProvider.set('requestStart' + resolvedDataKey, Date.now()) + requestInitialTimes.set(resolvedDataKey, Date.now()) const newRequestConfig = ( isRequest @@ -600,21 +607,21 @@ export function useFetch( ...reqConfig, ...optionsConfig, signal: (() => { - return newAbortController.signal; + return newAbortController.signal })(), headers: { - "Content-Type": "application/json", + 'Content-Type': 'application/json', ...ctx.headers, ..._headers, ...config.headers, - ...c.headers, - }, + ...c.headers + } } : { ...ctx, ...optionsConfig, signal: (() => { - return newAbortController.signal; + return newAbortController.signal })(), body: temporaryFormData.get(resolvedKey) ?? @@ -625,107 +632,107 @@ export function useFetch( headers: { ...(temporaryFormData.get(resolvedKey) ? {} - : { "Content-Type": "application/json" }), + : { 'Content-Type': 'application/json' }), ...ctx.headers, ...config.headers, - ...c.headers, - }, + ...c.headers + } } - ) as any; + ) as any const r = new Request( ( realUrl + - (realUrl.includes("?") + (realUrl.includes('?') ? c.query : c.query - ? "?" + c.query + ? '?' + c.query : c.query) - ).replace("?&", "?"), + ).replace('?&', '?'), newRequestConfig - ); + ) if (logStart) { - (onFetchStart as any)(r, optionsConfig, ctx); + ;(onFetchStart as any)(r, optionsConfig, ctx) } // @ts-ignore - This could use 'axios' or something similar - const json = await $fetch(r.url, newRequestConfig); + const json = await $fetch(r.url, newRequestConfig) - const resolvedDate = Date.now(); + const resolvedDate = Date.now() cacheProvider.set( - "expiration" + resolvedDataKey, + 'expiration' + resolvedDataKey, resolvedDate + maxAge - ); + ) - cacheProvider.set("requestEnds" + resolvedDataKey, resolvedDate); + cacheProvider.set('requestEnds' + resolvedDataKey, resolvedDate) requestResponseTimes.set( resolvedDataKey, getTimePassed(resolvedDataKey) - ); + ) - lastResponses.set(resolvedKey, json); + lastResponses.set(resolvedKey, json) - const code = json.status as number; - statusCodes.set(resolvedKey, code); + const code = json.status as number + statusCodes.set(resolvedKey, code) rpc = { ...rpc, response: json, error: false, - code, - }; + code + } // @ts-ignore - 'data' is priority because 'fetcher' can return it - const incoming = json?.["data"] ?? (await (resolver as any)(json)); + const incoming = json?.['data'] ?? (await (resolver as any)(json)) // @ts-ignore - const actionError = json?.["error"]; + const actionError = json?.['error'] const _data = isFunction(middleware) ? await middleware!(incoming as any, thisCache) - : incoming; + : incoming let __data = isGqlRequest ? { ..._data, variables: (optionsConfig as any)?.variables, - errors: _data?.errors ? _data.errors : undefined, + errors: _data?.errors ? _data.errors : undefined } - : _data; + : _data - cacheProvider.set(resolvedDataKey, __data); - cacheProvider.set(resolvedKey, __data); - valuesMemory.set(resolvedKey, __data); - $$data = __data; - cacheForMutation.set(idString, __data); + cacheProvider.set(resolvedDataKey, __data) + cacheProvider.set(resolvedKey, __data) + valuesMemory.set(resolvedKey, __data) + $$data = __data + cacheForMutation.set(idString, __data) if (code >= 200 && code < 400) { - gettingAttempts.set(resolvedKey, true); + gettingAttempts.set(resolvedKey, true) - hasData.set(resolvedDataKey, true); - hasData.set(resolvedKey, true); + hasData.set(resolvedDataKey, true) + hasData.set(resolvedKey, true) rpc = { ...rpc, - error: false, - }; + error: false + } - const dataExpirationTime = Date.now() + maxAge; - cacheProvider.set(ageKey, dataExpirationTime); + const dataExpirationTime = Date.now() + maxAge + cacheProvider.set(ageKey, dataExpirationTime) if (_data?.errors && isGqlRequest) { - hasErrors.set(resolvedDataKey, true); - hasErrors.set(resolvedKey, true); + hasErrors.set(resolvedDataKey, true) + hasErrors.set(resolvedKey, true) rpc = { ...rpc, - error: true, - }; + error: true + } if (handleError) { if (!resolvedOnErrorCalls.get(resolvedKey)) { - resolvedOnErrorCalls.set(resolvedKey, true); - (onError as any)(true); + resolvedOnErrorCalls.set(resolvedKey, true) + ;(onError as any)(true) } } } @@ -738,181 +745,181 @@ export function useFetch( variables: isGqlRequest ? (optionsConfig as any)?.variables || {} : undefined, - completedAttempts: 0, - }; + completedAttempts: 0 + } - $$data = __data; - cacheForMutation.set(idString, __data); + $$data = __data + cacheForMutation.set(idString, __data) if (!_data?.errors && isGqlRequest) { rpc = { ...rpc, - error: false, - }; + error: false + } - hasErrors.set(resolvedDataKey, false); - hasErrors.set(resolvedKey, false); + hasErrors.set(resolvedDataKey, false) + hasErrors.set(resolvedKey, false) } if (willResolve) { if (!resolvedHookCalls.get(resolvedKey)) { - (onResolve as any)(__data, lastResponses.get(resolvedKey)); + ;(onResolve as any)(__data, lastResponses.get(resolvedKey)) - resolvedHookCalls.set(resolvedKey, true); + resolvedHookCalls.set(resolvedKey, true) } } - runningRequests.set(resolvedKey, false); + runningRequests.set(resolvedKey, false) // If a request completes succesfuly, reset the error attempts to 0 queue(() => { - cacheForMutation.set(resolvedKey, __data); - }); + cacheForMutation.set(resolvedKey, __data) + }) } else { rpc = { ...rpc, - error: actionError ?? true, - }; + error: actionError ?? true + } if (!cacheIfError) { - hasData.set(resolvedDataKey, false); - hasData.set(resolvedKey, false); + hasData.set(resolvedDataKey, false) + hasData.set(resolvedKey, false) } if (_data.errors && isGqlRequest) { if (!cacheIfError) { - hasData.set(resolvedDataKey, false); - hasData.set(resolvedKey, false); + hasData.set(resolvedDataKey, false) + hasData.set(resolvedKey, false) } - setFetchState((previous) => { + setFetchState(previous => { const newData = { ...previous, variables: (optionsConfig as any)?.variables, - errors: _data.errors, - } as any; + errors: _data.errors + } as any - $$data = newData; + $$data = newData - cacheForMutation.set(idString, newData); + cacheForMutation.set(idString, newData) rpc = { ...rpc, data: newData, - error: actionError ?? true, - }; + error: actionError ?? true + } - cacheProvider.set(resolvedDataKey, newData); - cacheProvider.set(resolvedKey, newData); + cacheProvider.set(resolvedDataKey, newData) + cacheProvider.set(resolvedKey, newData) - return previous; - }); + return previous + }) if (handleError) { if (!resolvedOnErrorCalls.get(resolvedKey)) { - resolvedOnErrorCalls.set(resolvedKey, actionError ?? true); - (onError as any)(actionError ?? true, json); + resolvedOnErrorCalls.set(resolvedKey, actionError ?? true) + ;(onError as any)(actionError ?? true, json) } } } else { if (def) { - $$data = thisCache; - cacheForMutation.set(idString, def); + $$data = thisCache + cacheForMutation.set(idString, def) rpc = { ...rpc, - data: def, - }; + data: def + } } if (handleError) { if (!resolvedOnErrorCalls.get(resolvedKey)) { - resolvedOnErrorCalls.set(resolvedKey, actionError ?? true); - (onError as any)(_data, json); + resolvedOnErrorCalls.set(resolvedKey, actionError ?? true) + ;(onError as any)(_data, json) } } } - hasErrors.set(resolvedDataKey, actionError ?? true); - hasErrors.set(resolvedKey, actionError ?? true); - runningRequests.set(resolvedKey, false); + hasErrors.set(resolvedDataKey, actionError ?? true) + hasErrors.set(resolvedKey, actionError ?? true) + runningRequests.set(resolvedKey, false) } if (logEnd) { - (onFetchEnd as any)( + ;(onFetchEnd as any)( lastResponses.get(resolvedKey), optionsConfig, ctx - ); + ) } } catch (err) { - const errorString = err?.toString(); + const errorString = err?.toString() // Only set error if no abort // @ts-ignore if (!/abort/i.test(errorString)) { if (!cacheIfError) { - hasData.set(resolvedDataKey, false); - hasData.set(resolvedKey, false); + hasData.set(resolvedDataKey, false) + hasData.set(resolvedKey, false) } rpc = { ...rpc, - error: err ?? true, - }; + error: err ?? true + } if (cacheIfError) { if (notNull(thisCache) && isDefined(thisCache)) { - $$data = thisCache; - cacheForMutation.set(idString, thisCache); + $$data = thisCache + cacheForMutation.set(idString, thisCache) rpc = { ...rpc, - data: thisCache, - }; + data: thisCache + } } } else { - $$data = def; + $$data = def rpc = { ...rpc, - data: def, - }; + data: def + } - cacheForMutation.set(idString, def); + cacheForMutation.set(idString, def) } rpc = { ...rpc, - error: err ?? true, - }; + error: err ?? true + } - hasErrors.set(resolvedDataKey, err ?? true); - hasErrors.set(resolvedKey, err ?? true); + hasErrors.set(resolvedDataKey, err ?? true) + hasErrors.set(resolvedKey, err ?? true) if (handleError) { if (!resolvedOnErrorCalls.get(resolvedKey)) { - resolvedOnErrorCalls.set(resolvedKey, true); - (onError as any)(err as any); + resolvedOnErrorCalls.set(resolvedKey, true) + ;(onError as any)(err as any) } } } else { rpc = { ...rpc, - loading: true, - }; + loading: true + } if (!isPending(resolvedKey)) { if (!isDefined(cacheProvider.get(resolvedDataKey))) { if (isDefined(def)) { - $$data = def; - cacheForMutation.set(idString, def); + $$data = def + cacheForMutation.set(idString, def) } rpc = { ...rpc, data: def, - loading: true, - }; + loading: true + } } } } } finally { if (rpc.error) { - gettingAttempts.set(resolvedKey, false); + gettingAttempts.set(resolvedKey, false) } - temporaryFormData.delete(resolvedKey); - runningRequests.set(resolvedKey, false); - suspenseInitialized.set(resolvedKey, true); + temporaryFormData.delete(resolvedKey) + runningRequests.set(resolvedKey, false) + suspenseInitialized.set(resolvedKey, true) requestsProvider.emit(resolvedKey, { error: @@ -920,14 +927,14 @@ export function useFetch( hasErrors.get(resolvedDataKey) || false, ...rpc, - loading: false, - }); + loading: false + }) - willSuspend.set(resolvedKey, false); + willSuspend.set(resolvedKey, false) queue(() => { - canDebounce.set(resolvedKey, true); - }, debounce); - return $$data; + canDebounce.set(resolvedKey, true) + }, debounce) + return $$data } } } @@ -945,47 +952,47 @@ export function useFetch( requestCallId, memory, def, - loadingFirst, + loadingFirst ] - ); + ) useEffect(() => { - const { signal } = requestAbortController || {}; + const { signal } = requestAbortController || {} // Run onAbort callback const abortCallback = () => { if (loading) { if (isPending(resolvedKey)) { if (handleOnAbort) { - (onAbort as any)(); + ;(onAbort as any)() } } } - }; - signal?.addEventListener("abort", abortCallback); + } + signal?.addEventListener('abort', abortCallback) return () => { - signal?.removeEventListener("abort", abortCallback); - }; - }, [requestAbortController, resolvedKey, onAbort, loading]); + signal?.removeEventListener('abort', abortCallback) + } + }, [requestAbortController, resolvedKey, onAbort, loading]) const imperativeFetch = useMemo(() => { const __headers = { ...ctx.headers, - ...config.headers, - }; + ...config.headers + } const __params = { ...ctx.params, - ...config.params, - }; + ...config.params + } - const __baseUrl = isDefined(config.baseUrl) ? config.baseUrl : ctx.baseUrl; + const __baseUrl = isDefined(config.baseUrl) ? config.baseUrl : ctx.baseUrl return createImperativeFetch({ ...ctx, headers: __headers, baseUrl: __baseUrl, - params: __params, - }); - }, [serialize(ctx)]); + params: __params + }) + }, [serialize(ctx)]) useEffect(() => { async function waitFormUpdates(v: any) { @@ -995,21 +1002,21 @@ export function useFetch( error: $error, online, loading, - completedAttempts, - } = v || {}; + completedAttempts + } = v || {} if (isMutating) { if (serialize($data) !== serialize(cacheForMutation.get(resolvedKey))) { - cacheForMutation.set(idString, $data); + cacheForMutation.set(idString, $data) if (isMutating) { - forceMutate($data); + forceMutate($data) if (handleMutate) { - if (url === "") { - (onMutate as any)($data, imperativeFetch); + if (url === '') { + ;(onMutate as any)($data, imperativeFetch) } else { if (!runningMutate.get(resolvedKey)) { - runningMutate.set(resolvedKey, true); - (onMutate as any)($data, imperativeFetch); + runningMutate.set(resolvedKey, true) + ;(onMutate as any)($data, imperativeFetch) } } } @@ -1020,89 +1027,89 @@ export function useFetch( if (v.requestCallId !== requestCallId) { if (!willSuspend.get(resolvedKey)) { queue(() => { - if (inDeps("data")) { + if (inDeps('data')) { if (isDefined($data)) { if (!jsonCompare(data, cacheProvider.get(resolvedDataKey))) { - setData(cacheProvider.get(resolvedKey)); + setData(cacheProvider.get(resolvedKey)) } } } - if (inDeps("online")) { + if (inDeps('online')) { if (isDefined(online)) { - setOnline(online); + setOnline(online) } } - if (inDeps("loading")) { + if (inDeps('loading')) { if (isDefined(loading)) { - setLoading(loading); + setLoading(loading) } } - if (inDeps("error")) { + if (inDeps('error')) { if (isDefined($error)) { if (fetchState.error !== $error) { - setError($error); + setError($error) } } } - if (inDeps("completedAttempts")) { + if (inDeps('completedAttempts')) { if (isDefined(completedAttempts)) { - setCompletedAttempts(completedAttempts); + setCompletedAttempts(completedAttempts) } } - }); + }) } } } - requestsProvider.addListener(resolvedKey, waitFormUpdates); + requestsProvider.addListener(resolvedKey, waitFormUpdates) return () => { - requestsProvider.removeListener(resolvedKey, waitFormUpdates); - }; + requestsProvider.removeListener(resolvedKey, waitFormUpdates) + } }, [ thisDeps, JSON.stringify(optionsConfig), resolvedKey, resolvedDataKey, requestCallId, - fetchState, - ]); + fetchState + ]) const reValidate = useCallback( async function reValidate() { if (!isPending(resolvedKey)) { - revalidate(id); + revalidate(id) } }, [serialize(id), loading] - ); + ) useEffect(() => { function forceRefresh() { if (!isPending(resolvedKey)) { // preventing revalidation where only need updates about // 'loading', 'error' and 'data' because the url can be ommited. - if (url !== "") { + if (url !== '') { fetchData({ query: Object.keys(reqQuery) - .map((q) => + .map(q => Array.isArray(reqQuery[q]) ? reqQuery[q] - .map((queryItem: any) => [q, queryItem].join("=")) - .join("&") - : [q, reqQuery[q]].join("=") + .map((queryItem: any) => [q, queryItem].join('=')) + .join('&') + : [q, reqQuery[q]].join('=') ) - .join("&"), - params: reqParams, - }); + .join('&'), + params: reqParams + }) } } } - let idString = serialize(id); - requestsProvider.addListener(idString, forceRefresh); + let idString = serialize(id) + requestsProvider.addListener(idString, forceRefresh) return () => { - requestsProvider.removeListener(idString, forceRefresh); - }; + requestsProvider.removeListener(idString, forceRefresh) + } }, [ fetchState, resolvedKey, @@ -1114,116 +1121,116 @@ export function useFetch( ctx.auto, idString, fetchState, - id, - ]); + id + ]) useEffect(() => { function backOnline() { - let willCancel = false; + let willCancel = false function cancelReconectionAttempt() { - willCancel = true; + willCancel = true } requestsProvider.emit(resolvedKey, { requestCallId, - online: true, - }); - setOnline(true); - offlineHandled.set(resolvedKey, false); + online: true + }) + setOnline(true) + offlineHandled.set(resolvedKey, false) if (handleOnline) { if (!onlineHandled.get(resolvedKey)) { - onlineHandled.set(resolvedKey, true); - (onOnline as any)({ cancel: cancelReconectionAttempt }); + onlineHandled.set(resolvedKey, true) + ;(onOnline as any)({ cancel: cancelReconectionAttempt }) } } if (!willCancel) { - reValidate(); + reValidate() } } function addOnlineListener() { if (windowExists) { - if ("addEventListener" in window) { + if ('addEventListener' in window) { if (retryOnReconnect) { - window.addEventListener("online", backOnline); + window.addEventListener('online', backOnline) } } } } - addOnlineListener(); + addOnlineListener() return () => { if (windowExists) { - if ("addEventListener" in window) { - window.removeEventListener("online", backOnline); + if ('addEventListener' in window) { + window.removeEventListener('online', backOnline) } } - }; - }, [onOnline, reValidate, requestCallId, resolvedKey, retryOnReconnect]); + } + }, [onOnline, reValidate, requestCallId, resolvedKey, retryOnReconnect]) useEffect(() => { function wentOffline() { - runningRequests.set(resolvedKey, false); - setOnline(false); + runningRequests.set(resolvedKey, false) + setOnline(false) requestsProvider.emit(resolvedKey, { requestCallId, - online: false, - }); - onlineHandled.set(resolvedKey, false); + online: false + }) + onlineHandled.set(resolvedKey, false) if (handleOffline) { if (!offlineHandled.get(resolvedKey)) { - offlineHandled.set(resolvedKey, true); - (onOffline as any)(); + offlineHandled.set(resolvedKey, true) + ;(onOffline as any)() } } } function addOfflineListener() { if (windowExists) { - if ("addEventListener" in window) { - window.addEventListener("offline", wentOffline); + if ('addEventListener' in window) { + window.addEventListener('offline', wentOffline) } } } - addOfflineListener(); + addOfflineListener() return () => { if (windowExists) { - if ("addEventListener" in window) { - window.removeEventListener("offline", wentOffline); + if ('addEventListener' in window) { + window.removeEventListener('offline', wentOffline) } } - }; - }, [onOffline, reValidate, requestCallId, resolvedKey, retryOnReconnect]); + } + }, [onOffline, reValidate, requestCallId, resolvedKey, retryOnReconnect]) useEffect(() => { return () => { if (revalidateOnMount) { if (canRevalidate) { - if (url !== "") { + if (url !== '') { if (suspenseInitialized.get(resolvedKey)) { queue(() => { - previousConfig.set(resolvedKey, undefined); - hasErrors.set(resolvedKey, false); - hasErrors.set(resolvedDataKey, false); - runningRequests.set(resolvedKey, false); + previousConfig.set(resolvedKey, undefined) + hasErrors.set(resolvedKey, false) + hasErrors.set(resolvedDataKey, false) + runningRequests.set(resolvedKey, false) // Wait for 100ms after suspense unmount - }, 100); + }, 100) } else { - previousConfig.set(resolvedKey, undefined); - hasErrors.set(resolvedKey, false); - hasErrors.set(resolvedDataKey, false); - runningRequests.set(resolvedKey, false); + previousConfig.set(resolvedKey, undefined) + hasErrors.set(resolvedKey, false) + hasErrors.set(resolvedDataKey, false) + runningRequests.set(resolvedKey, false) } } } } - }; - }, [requestCallId, resolvedKey, revalidateOnMount, suspense]); + } + }, [requestCallId, resolvedKey, revalidateOnMount, suspense]) if (!gettingAttempts.has(resolvedKey)) { - gettingAttempts.set(resolvedKey, false); + gettingAttempts.set(resolvedKey, false) } useEffect(() => { @@ -1232,9 +1239,9 @@ export function useFetch( // if ((attempts as number) > 0) { const tm = setTimeout(() => { if (!gettingAttempts.get(resolvedKey)) { - gettingAttempts.set(resolvedKey, true); + gettingAttempts.set(resolvedKey, true) const attempts = - typeof $attempts === "function" + typeof $attempts === 'function' ? $attempts({ status: statusCodes.get(resolvedKey) || @@ -1244,38 +1251,38 @@ export function useFetch( hasErrors.get(resolvedKey) || hasErrors.get(resolvedDataKey) || (error as any), - completedAttempts, + completedAttempts }) - : $attempts; + : $attempts if ((attempts as number) > 0) { if (completedAttempts < (attempts as number)) { - reValidate(); + reValidate() setCompletedAttempts((previousAttempts: number) => { - let newAttemptsValue = previousAttempts + 1; + let newAttemptsValue = previousAttempts + 1 requestsProvider.emit(resolvedKey, { requestCallId, - completedAttempts: newAttemptsValue, - }); + completedAttempts: newAttemptsValue + }) - return newAttemptsValue; - }); + return newAttemptsValue + }) } else if (completedAttempts === attempts) { requestsProvider.emit(resolvedKey, { requestCallId, online: false, - error: true, - }); - if (inDeps("online")) setOnline(false); + error: true + }) + if (inDeps('online')) setOnline(false) } } } - }, getMiliseconds(attemptInterval as TimeSpan)); + }, getMiliseconds(attemptInterval as TimeSpan)) // } return () => { - clearTimeout(tm); - }; + clearTimeout(tm) + } }, [ error, $attempts, @@ -1285,21 +1292,21 @@ export function useFetch( fetchState, attemptInterval, resolvedKey, - completedAttempts, - ]); + completedAttempts + ]) useEffect(() => { - const refreshAmount = getMiliseconds(refresh as TimeSpan); + const refreshAmount = getMiliseconds(refresh as TimeSpan) if (completedAttempts === 0) { if (refreshAmount > 0 && canRevalidate) { - const tm = setInterval(reValidate, refreshAmount); + const tm = setInterval(reValidate, refreshAmount) return () => { - clearInterval(tm); - }; + clearInterval(tm) + } } } - return () => {}; + return () => {} // eslint-disable-next-line react-hooks/exhaustive-deps }, [ refresh, @@ -1308,75 +1315,75 @@ export function useFetch( rawJSON, canRevalidate, completedAttempts, - config, - ]); + config + ]) const initializeRevalidation = useCallback( windowExists ? async function initializeRevalidation() { - let d = undefined; + let d = undefined if (canRevalidate) { - if (url !== "") { + if (url !== '') { d = await fetchData({ query: Object.keys(reqQuery) - .map((q) => + .map(q => Array.isArray(reqQuery[q]) ? reqQuery[q] - .map((queryItem: any) => [q, queryItem].join("=")) - .join("&") - : [q, reqQuery[q]].join("=") + .map((queryItem: any) => [q, queryItem].join('=')) + .join('&') + : [q, reqQuery[q]].join('=') ) - .join("&"), - params: reqParams, - }); + .join('&'), + params: reqParams + }) } else { - d = def; + d = def // It means a url is not passed - setFetchState((prev) => ({ + setFetchState(prev => ({ ...prev, loading: false, error: hasErrors.get(resolvedDataKey) || hasErrors.get(resolvedKey), - completedAttempts: prev.completedAttempts, - })); + completedAttempts: prev.completedAttempts + })) } } else { - d = def; + d = def } - return d; + return d } : () => { return new Promise((resolve, reject) => { - queue(() => resolve(initialDataValue)); - }); + queue(() => resolve(initialDataValue)) + }) }, [serialize(serialize(optionsConfig)), fetchState, thisDeps] - ); + ) if (!suspense) { - if (url !== "") { - suspenseInitialized.set(resolvedKey, true); + if (url !== '') { + suspenseInitialized.set(resolvedKey, true) } } useIsomorphicLayoutEffect(() => { const fn = () => { - if (url !== "") { + if (url !== '') { if (!jsonCompare(previousProps.get(resolvedKey), optionsConfig)) { - abortControllers.get(resolvedKey)?.abort(); - if (inDeps("data")) { - queue(initializeRevalidation); + abortControllers.get(resolvedKey)?.abort() + if (inDeps('data')) { + queue(initializeRevalidation) } } } - }; + } if (debounce) { - const tm = setTimeout(fn, debounce); - return () => clearTimeout(tm); + const tm = setTimeout(fn, debounce) + return () => clearTimeout(tm) } - fn(); - return () => {}; - }, [serialize(optionsConfig), thisDeps, fetchState]); + fn() + return () => {} + }, [serialize(optionsConfig), thisDeps, fetchState]) if (suspense) { if (auto) { @@ -1386,10 +1393,10 @@ export function useFetch( suspenseRevalidationStarted.set( resolvedKey, initializeRevalidation() - ); + ) } - throw suspenseRevalidationStarted.get(resolvedKey); + throw suspenseRevalidationStarted.get(resolvedKey) } } @@ -1404,7 +1411,7 @@ import { Suspense } from "http-react" Learn more: https://httpr.vercel.app/docs/api#suspense ` - ); + ) } } } @@ -1413,47 +1420,47 @@ Learn more: https://httpr.vercel.app/docs/api#suspense const fn = () => { if (!runningRequests.get(resolvedKey) && canRevalidate) { if (windowExists) { - if (canRevalidate && url !== "") { + if (canRevalidate && url !== '') { if ( !jsonCompare( - JSON.parse(previousConfig.get(resolvedKey) || "{}"), + JSON.parse(previousConfig.get(resolvedKey) || '{}'), optionsConfig ) ) { if (!isPending(resolvedKey)) { - if (inDeps("data")) { - initializeRevalidation(); + if (inDeps('data')) { + initializeRevalidation() } } else { - setLoading(true); + setLoading(true) } } } } } - }; + } if (debounce) { - const tm = setTimeout(fn, debounce); - return () => clearTimeout(tm); + const tm = setTimeout(fn, debounce) + return () => clearTimeout(tm) } - fn(); + fn() - return () => {}; - }, [resolvedKey, serialize(optionsConfig), canRevalidate, thisDeps]); + return () => {} + }, [resolvedKey, serialize(optionsConfig), canRevalidate, thisDeps]) useIsomorphicLayoutEffect(() => { const revalidateAfterUnmount = revalidateOnMount ? true : !jsonCompare( - JSON.parse(previousConfig.get(resolvedKey) || "{}"), + JSON.parse(previousConfig.get(resolvedKey) || '{}'), optionsConfig - ); + ) function revalidate() { if (!debounce && !canDebounce.get(resolvedKey)) { - if (inDeps("data")) { - initializeRevalidation(); + if (inDeps('data')) { + initializeRevalidation() } } } @@ -1462,43 +1469,43 @@ Learn more: https://httpr.vercel.app/docs/api#suspense if (revalidateAfterUnmount) { if (suspense) { if (suspenseInitialized.get(resolvedKey)) { - revalidate(); + revalidate() } } else { - revalidate(); + revalidate() } } - }; + } if (debounce) { - const tm = setTimeout(fn, debounce); - return () => clearTimeout(tm); + const tm = setTimeout(fn, debounce) + return () => clearTimeout(tm) } - fn(); + fn() - return () => {}; + return () => {} // eslint-disable-next-line react-hooks/exhaustive-deps - }, [serialize(optionsConfig), thisDeps]); + }, [serialize(optionsConfig), thisDeps]) useEffect(() => { function addFocusListener() { if (revalidateOnFocus && windowExists) { - if ("addEventListener" in window) { - window.addEventListener("focus", reValidate as any); + if ('addEventListener' in window) { + window.addEventListener('focus', reValidate as any) } } } - if (auto) addFocusListener(); + if (auto) addFocusListener() return () => { if (windowExists) { - if ("addEventListener" in window) { - window.removeEventListener("focus", reValidate as any); + if ('addEventListener' in window) { + window.removeEventListener('focus', reValidate as any) } } - }; + } }, [ requestCallId, url, @@ -1507,8 +1514,8 @@ Learn more: https://httpr.vercel.app/docs/api#suspense loading, reValidate, refresh, - serialize(config), - ]); + serialize(config) + ]) const __config = { ...config, @@ -1516,21 +1523,21 @@ Learn more: https://httpr.vercel.app/docs/api#suspense ...previousProps.get(resolvedKey), params: { ...reqParams, - ...previousProps.get(resolvedKey)?.params, + ...previousProps.get(resolvedKey)?.params }, headers: { ...requestHeaders, - ...previousProps.get(resolvedKey)?.headers, + ...previousProps.get(resolvedKey)?.headers }, body: config.body, baseUrl: ctx.baseUrl || config.baseUrl, - url: configUrl?.realUrl?.replace("?", ""), + url: configUrl?.realUrl?.replace('?', ''), rawUrl: configUrl?.rawUrl, query: { ...reqQuery, - ...previousProps.get(resolvedKey)?.query, - }, - }; + ...previousProps.get(resolvedKey)?.query + } + } function forceMutate( newValue: FetchDataType | ((prev: FetchDataType) => FetchDataType), @@ -1540,47 +1547,47 @@ Learn more: https://httpr.vercel.app/docs/api#suspense if ( serialize(cacheProvider.get(resolvedDataKey)) !== serialize(newValue) ) { - callback(newValue as any, imperativeFetch); - cacheProvider.set(resolvedDataKey, newValue); - cacheProvider.set(resolvedKey, newValue); - valuesMemory.set(resolvedKey, newValue); - cacheForMutation.set(idString, newValue); - runningMutate.set(resolvedKey, false); + callback(newValue as any, imperativeFetch) + cacheProvider.set(resolvedDataKey, newValue) + cacheProvider.set(resolvedKey, newValue) + valuesMemory.set(resolvedKey, newValue) + cacheForMutation.set(idString, newValue) + runningMutate.set(resolvedKey, false) requestsProvider.emit(resolvedKey, { requestCallId, isMutating: true, - data: newValue, - }); - setData(newValue as any); + data: newValue + }) + setData(newValue as any) } } else { - let newVal = (newValue as any)(data); + let newVal = (newValue as any)(data) if (serialize(cacheProvider.get(resolvedDataKey)) !== serialize(newVal)) { - callback(newVal, imperativeFetch); - cacheProvider.set(resolvedDataKey, newVal); - cacheProvider.set(resolvedKey, newVal); - valuesMemory.set(resolvedKey, newVal); - cacheForMutation.set(idString, newVal); - runningMutate.set(resolvedKey, false); + callback(newVal, imperativeFetch) + cacheProvider.set(resolvedDataKey, newVal) + cacheProvider.set(resolvedKey, newVal) + valuesMemory.set(resolvedKey, newVal) + cacheForMutation.set(idString, newVal) + runningMutate.set(resolvedKey, false) requestsProvider.emit(resolvedKey, { requestCallId, isMutating: true, - data: newVal, - }); + data: newVal + }) - setData(newVal); + setData(newVal) } } } const [$requestStart, $requestEnd] = [ - notNull(cacheProvider.get("requestStart" + resolvedDataKey)) - ? new Date(cacheProvider.get("requestStart" + resolvedDataKey)) - : null, - notNull(cacheProvider.get("requestEnds" + resolvedDataKey)) - ? new Date(cacheProvider.get("requestEnds" + resolvedDataKey)) + notNull(cacheProvider.get('requestStart' + resolvedDataKey)) + ? new Date(cacheProvider.get('requestStart' + resolvedDataKey)) : null, - ]; + notNull(cacheProvider.get('requestEnds' + resolvedDataKey)) + ? new Date(cacheProvider.get('requestEnds' + resolvedDataKey)) + : null + ] const expirationDate = error ? notNull($requestEnd) @@ -1588,40 +1595,38 @@ Learn more: https://httpr.vercel.app/docs/api#suspense : null : maxAge === 0 ? null - : notNull(cacheProvider.get("expiration" + resolvedDataKey)) - ? new Date(cacheProvider.get("expiration" + resolvedDataKey)) - : null; + : notNull(cacheProvider.get('expiration' + resolvedDataKey)) + ? new Date(cacheProvider.get('expiration' + resolvedDataKey)) + : null const isFailed = - hasErrors.get(resolvedDataKey) || hasErrors.get(resolvedKey) || error; + hasErrors.get(resolvedDataKey) || hasErrors.get(resolvedKey) || error const dataCandidate = - (error && isFailed ? (cacheIfError ? thisCache : null) : thisCache) ?? def; + (error && isFailed ? (cacheIfError ? thisCache : null) : thisCache) ?? def const responseData = isDefined(dataCandidate) ? transform!(dataCandidate) - : dataCandidate; + : dataCandidate - const isSuccess = !isLoading && !isFailed; + const isSuccess = !isLoading && !isFailed const oneRequestResolved = !loadingFirst && (hasData.get(resolvedDataKey) || hasData.get(resolvedKey) || - (cacheIfError - ? isDefined(responseData) && notNull(responseData) - : false)); + (cacheIfError ? isDefined(responseData) && notNull(responseData) : false)) const submit = useCallback( (form: FormData) => { if (isFormData(form)) { if (formRef.current) { if (onSubmit) { - if (onSubmit !== "reset") { - onSubmit(formRef.current, form); + if (onSubmit !== 'reset') { + onSubmit(formRef.current, form) } else { if (formRef.current) { - formRef.current.reset(); + formRef.current.reset() } } } @@ -1630,200 +1635,200 @@ Learn more: https://httpr.vercel.app/docs/api#suspense temporaryFormData.set( resolvedKey, isFormData(form) ? form : serialize(form) - ); - reValidate(); + ) + reValidate() }, [resolvedKey, formRef.current, reValidate] - ); + ) function resetError() { - hasErrors.set(resolvedKey, false); - hasErrors.set(resolvedDataKey, false); + hasErrors.set(resolvedKey, false) + hasErrors.set(resolvedDataKey, false) requestsProvider.emit(resolvedKey, { - error: false, - }); + error: false + }) } const refreshRequest = () => { - revalidate(id); - }; + revalidate(id) + } return { get resetError() { - thisDeps.error = true; - return resetError; + thisDeps.error = true + return resetError }, formProps: { action: submit, - ref: formRef, + ref: formRef }, formRef, get revalidating() { - thisDeps.loading = true; - return oneRequestResolved && isLoading; + thisDeps.loading = true + return oneRequestResolved && isLoading }, get isRevalidating() { - thisDeps.loading = true; - return oneRequestResolved && isLoading; + thisDeps.loading = true + return oneRequestResolved && isLoading }, get hasData() { - thisDeps.data = true; - return oneRequestResolved; + thisDeps.data = true + return oneRequestResolved }, get success() { - thisDeps.loading = true; - thisDeps.error = true; - return isSuccess; + thisDeps.loading = true + thisDeps.error = true + return isSuccess }, get loadingFirst() { - thisDeps.loading = true; - return loadingFirst; + thisDeps.loading = true + return loadingFirst }, get isLoadingFirst() { - thisDeps.loading = true; - return loadingFirst; + thisDeps.loading = true + return loadingFirst }, get requestStart() { - thisDeps.loading = true; - return getDateIfValid($requestStart); + thisDeps.loading = true + return getDateIfValid($requestStart) }, get requestEnd() { - thisDeps.loading = true; - return getDateIfValid($requestEnd); + thisDeps.loading = true + return getDateIfValid($requestEnd) }, get expiration() { - thisDeps.loading = true; - return getDateIfValid(isFailed ? null : expirationDate); + thisDeps.loading = true + return getDateIfValid(isFailed ? null : expirationDate) }, get responseTime() { - thisDeps.loading = true; - return requestResponseTimes.get(resolvedDataKey) ?? null; + thisDeps.loading = true + return requestResponseTimes.get(resolvedDataKey) ?? null }, get data() { - thisDeps.data = true; - return responseData; + thisDeps.data = true + return responseData }, get loading() { - thisDeps.loading = true; - return isLoading; + thisDeps.loading = true + return isLoading }, get isLoading() { - thisDeps.loading = true; - return isLoading; + thisDeps.loading = true + return isLoading }, get isPending() { - thisDeps.loading = true; - return isLoading; + thisDeps.loading = true + return isLoading }, get error() { - thisDeps.error = true; - return isFailed || false; + thisDeps.error = true + return isFailed || false }, get online() { - thisDeps.online = true; - return online; + thisDeps.online = true + return online }, get code() { - thisDeps.loading = true; - return statusCodes.get(resolvedKey); + thisDeps.loading = true + return statusCodes.get(resolvedKey) }, refresh: refreshRequest, get reFetch() { - thisDeps.loading = true; - return reValidate; + thisDeps.loading = true + return reValidate }, submit, get mutate() { - thisDeps.data = true; - return forceMutate; + thisDeps.data = true + return forceMutate }, get fetcher() { - return imperativeFetch; + return imperativeFetch }, get abort() { return () => { - abortControllers.get(resolvedKey)?.abort(); + abortControllers.get(resolvedKey)?.abort() if (loading) { - setError(false); - hasErrors.set(resolvedDataKey, false); - setLoading(false); - setData(requestCache); + setError(false) + hasErrors.set(resolvedDataKey, false) + setLoading(false) + setData(requestCache) requestsProvider.emit(resolvedKey, { requestCallId, error: false, loading: false, - data: requestCache, - }); + data: requestCache + }) } - }; + } }, config: __config, get response() { - thisDeps.loading = true; - return lastResponses.get(resolvedKey); + thisDeps.loading = true + return lastResponses.get(resolvedKey) }, id, /** * The request key */ - key: resolvedKey, + key: id } as unknown as { - refresh(): void; - resetError(): void; + refresh(): void + resetError(): void formProps: { - action: (form: FormData) => Promise; - ref: typeof formRef; - }; - formRef: typeof formRef; - hasData: boolean; + action: (form: FormData) => Promise + ref: typeof formRef + } + formRef: typeof formRef + hasData: boolean /** * Revalidating means that at least one request has finished succesfuly and a new request is being sent */ - revalidating: boolean; - success: boolean; - loadingFirst: boolean; - isLoadingFirst: boolean; - expiration: Date; - data: FetchDataType; - isPending?: boolean; - loading: boolean; - isLoading: boolean; - isRevalidating: boolean; - error: any; - online: boolean; - code: number; - reFetch: () => Promise; - submit: (submitData: any) => Promise; + revalidating: boolean + success: boolean + loadingFirst: boolean + isLoadingFirst: boolean + expiration: Date + data: FetchDataType + isPending?: boolean + loading: boolean + isLoading: boolean + isRevalidating: boolean + error: any + online: boolean + code: number + reFetch: () => Promise + submit: (submitData: any) => Promise mutate: ( update: FetchDataType | ((prev: FetchDataType) => FetchDataType), callback?: (data: FetchDataType, fetcher: ImperativeFetch) => void - ) => FetchDataType; - fetcher: ImperativeFetch; - abort: () => void; + ) => FetchDataType + fetcher: ImperativeFetch + abort: () => void config: FetchConfigType & { - baseUrl: string; - url: string; - rawUrl: string; - }; - response: CustomResponse; - id: any; - key: string; - responseTime: number; - requestStart: Date; - requestEnd: Date; - }; + baseUrl: string + url: string + rawUrl: string + } + response: CustomResponse + id: any + key: string + responseTime: number + requestStart: Date + requestEnd: Date + } } -useFetch.get = createRequestFn("GET", "", {}); -useFetch.delete = createRequestFn("DELETE", "", {}); -useFetch.head = createRequestFn("HEAD", "", {}); -useFetch.options = createRequestFn("OPTIONS", "", {}); -useFetch.post = createRequestFn("POST", "", {}); -useFetch.put = createRequestFn("PUT", "", {}); -useFetch.patch = createRequestFn("PATCH", "", {}); -useFetch.purge = createRequestFn("PURGE", "", {}); -useFetch.link = createRequestFn("LINK", "", {}); -useFetch.unlink = createRequestFn("UNLINK", "", {}); - -useFetch.extend = createImperativeFetch; +useFetch.get = createRequestFn('GET', '', {}) +useFetch.delete = createRequestFn('DELETE', '', {}) +useFetch.head = createRequestFn('HEAD', '', {}) +useFetch.options = createRequestFn('OPTIONS', '', {}) +useFetch.post = createRequestFn('POST', '', {}) +useFetch.put = createRequestFn('PUT', '', {}) +useFetch.patch = createRequestFn('PATCH', '', {}) +useFetch.purge = createRequestFn('PURGE', '', {}) +useFetch.link = createRequestFn('LINK', '', {}) +useFetch.unlink = createRequestFn('UNLINK', '', {}) + +useFetch.extend = createImperativeFetch diff --git a/src/index.ts b/src/index.ts index 6b483dc..5560c5c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,11 +6,11 @@ * LICENSE file in the root directory of this source tree. */ -export type { CacheStoreType, FetchInit } from "./types"; +export type { CacheStoreType, FetchInit } from './types' -import { useFetch } from "./hooks"; +import { useFetch } from './hooks' -export default useFetch; +export default useFetch export { useData, @@ -52,22 +52,23 @@ export { useMutation, useServerAction, useServerMutation, - useAction, -} from "./hooks"; + useAction +} from './hooks' -export { FetchConfig, SSRSuspense } from "./components/server"; -export { SSRSuspense as Suspense } from "./components/server"; +export { FetchConfig, SSRSuspense } from './components/server' +export { SSRSuspense as Suspense } from './components/server' export { queryProvider, mutateData, revalidate, cancelRequest, + revalidateKey, getMiliseconds, - fetchOptions, -} from "./utils"; + fetchOptions +} from './utils' -export { defaultCache } from "./internal"; +export { defaultCache } from './internal' export { Client, @@ -89,5 +90,5 @@ export { windowExists, queue, gql, - getRequestHeaders as $headers, -} from "./utils/shared"; + getRequestHeaders as $headers +} from './utils/shared' diff --git a/src/types/index.ts b/src/types/index.ts index 41fb528..37d3fa8 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,29 +1,29 @@ export type HTTP_METHODS = - | "GET" - | "DELETE" - | "HEAD" - | "OPTIONS" - | "POST" - | "PUT" - | "PATCH" - | "PURGE" - | "LINK" - | "UNLINK"; + | 'GET' + | 'DELETE' + | 'HEAD' + | 'OPTIONS' + | 'POST' + | 'PUT' + | 'PATCH' + | 'PURGE' + | 'LINK' + | 'UNLINK' export type FetchContextType = { - clientOnly?: boolean; + clientOnly?: boolean fetcher?( url: string, config: FetchConfigType ): Promise<{ - json?: any; - data?: any; - status?: number; - blob?: any; - text?: any; - }>; - headers?: any; - baseUrl?: string; + json?: any + data?: any + status?: number + blob?: any + text?: any + }> + headers?: any + baseUrl?: string /** * Sets the default (placeholder) value of request data. * @@ -37,63 +37,63 @@ export type FetchContextType = { * } */ value?: { - [key: string]: any; - }; + [key: string]: any + } defaults?: { [key: string]: { /** * The `id` passed to the request */ - id?: any; + id?: any /** * Default value for this request */ - value?: any; - method?: HTTP_METHODS; - }; - }; - suspense?: any[]; - resolver?: (r: Response) => any; - middleware?(incomindgData: any, previousData: any): any; - transform?(fetchData: any): any; - children?: any; - auto?: boolean; - memory?: boolean; - refresh?: TimeSpan; - attempts?: number; - attemptInterval?: TimeSpan; - revalidateOnFocus?: boolean; - query?: any; - params?: any; - onOnline?: (e: { cancel: () => void }) => void; - onOffline?: () => void; - online?: boolean; - retryOnReconnect?: boolean; - cacheProvider?: CacheStoreType; - revalidateOnMount?: boolean; - cacheIfError?: boolean; + value?: any + method?: HTTP_METHODS + } + } + suspense?: any[] + resolver?: (r: Response) => any + middleware?(incomindgData: any, previousData: any): any + transform?(fetchData: any): any + children?: any + auto?: boolean + memory?: boolean + refresh?: TimeSpan + attempts?: number + attemptInterval?: TimeSpan + revalidateOnFocus?: boolean + query?: any + params?: any + onOnline?: (e: { cancel: () => void }) => void + onOffline?: () => void + online?: boolean + retryOnReconnect?: boolean + cacheProvider?: CacheStoreType + revalidateOnMount?: boolean + cacheIfError?: boolean onFetchStart?( req: Request, config: FetchConfigType, ctx: FetchContextType - ): void; + ): void onFetchEnd?( res: Response, config: FetchConfigType, ctx: FetchContextType - ): void; - maxCacheAge?: TimeSpan; -} & Omit; + ): void + maxCacheAge?: TimeSpan +} & Omit export type CacheStoreType = { - get(k?: any): any; - set(k?: any, v?: any): any; - remove?(k?: any): any; -}; + get(k?: any): any + set(k?: any, v?: any): any + remove?(k?: any): any +} -export type CustomResponse = Omit & { - json(): Promise; -}; +export type CustomResponse = Omit & { + json(): Promise +} export type RequestWithBody = ( /** @@ -103,71 +103,75 @@ export type RequestWithBody = ( /** * The request configuration */ - reqConfig?: Omit, "suspense"> & { + reqConfig?: Omit, 'suspense'> & { /** * Default value */ - default?: R; + default?: R /** * Request query */ - query?: any; + query?: any /** * The function that formats the body */ - formatBody?: any; + formatBody?: any /** * Request params (like Express) */ - params?: any; + params?: any /** * The function that returns the resolved data */ - resolver?: (r: CustomResponse) => any; + resolver?: (r: CustomResponse) => any /** * A function that will run when the request fails */ - onError?(error: Error): void; + onError?(error: Error): void /** * A function that will run when the request completes succesfuly */ - onResolve?(data: R, res: CustomResponse): void; - cacheProvider?: CacheStoreType; + onResolve?(data: R, res: CustomResponse): void + cacheProvider?: CacheStoreType } ) => Promise<{ - error: any; - data: R; - config: RequestInit; - status: number; - res: CustomResponse; -}>; + error: any + data: R + config: RequestInit + status: number + res: CustomResponse +}> export type TimeSpan = | number - | `${string} ${"ms" | "sec" | "min" | "h" | "d" | "we" | "mo" | "y"}`; + | `${string} ${'ms' | 'sec' | 'min' | 'h' | 'd' | 'we' | 'mo' | 'y'}` /** * An imperative version of the `useFetch` hook */ export type ImperativeFetch = { - get: RequestWithBody; - delete: RequestWithBody; - head: RequestWithBody; - options: RequestWithBody; - post: RequestWithBody; - put: RequestWithBody; - patch: RequestWithBody; - purge: RequestWithBody; - link: RequestWithBody; - unlink: RequestWithBody; - config?: FetchContextType & FetchInit; -}; + get: RequestWithBody + delete: RequestWithBody + head: RequestWithBody + options: RequestWithBody + post: RequestWithBody + put: RequestWithBody + patch: RequestWithBody + purge: RequestWithBody + link: RequestWithBody + unlink: RequestWithBody + config?: FetchContextType & FetchInit +} export type FetchConfigType = Omit< RequestInit, - "body" | "headers" + 'body' | 'headers' > & { - headers?: any; + headers?: any + /** + * The fetch key + */ + key?: any /** * The middleware function should return the data that will be commited to the state. It can be used for pagination, logging, etc. * @@ -176,58 +180,58 @@ export type FetchConfigType = Omit< middleware?( incomindgData: FetchDataType, previousData: FetchDataType - ): FetchDataType; - transform?(fetchData: FetchDataType): FetchDataType; + ): FetchDataType + transform?(fetchData: FetchDataType): FetchDataType fetcher?( url: string, config: FetchConfigType ): Promise<{ - json?: any; - data?: FetchDataType; - status?: number; - blob?: any; - text?: any; - }>; - body?: any; + json?: any + data?: FetchDataType + status?: number + blob?: any + text?: any + }> + body?: any /** * Any serializable id. This is optional. */ - id?: any; + id?: any /** * url of the resource to fetch */ - url?: string; + url?: string /** * Default data value */ - default?: FetchDataType; + default?: FetchDataType /** * Refresh interval (in seconds) to re-fetch the resource * @default 0 */ - refresh?: TimeSpan; + refresh?: TimeSpan /** * This will prevent automatic requests. * By setting this to `false`, requests will * only be made by calling `reFetch()` * @default true */ - auto?: boolean; + auto?: boolean /** * Responses are saved in memory and used as default data. * If `false`, the `default` prop will be used instead. * @default true */ - memory?: boolean; - onSubmit?: "reset" | ((form: HTMLFormElement, data: FormData) => void); + memory?: boolean + onSubmit?: 'reset' | ((form: HTMLFormElement, data: FormData) => void) /** * Function to run when request is resolved succesfuly */ - onResolve?: (data: FetchDataType, res?: Response) => void; + onResolve?: (data: FetchDataType, res?: Response) => void /** * Override the cache for this specific request */ - cacheProvider?: CacheStoreType; + cacheProvider?: CacheStoreType /** * Function to run when data is mutated */ @@ -237,23 +241,23 @@ export type FetchConfigType = Omit< * An imperative version of `useFetche` */ fetcher: ImperativeFetch - ) => void; + ) => void /** * Function to run when the request fails */ - onError?: (error: Error, req?: Response) => void; + onError?: (error: Error, req?: Response) => void /** * Function to run when a request is aborted */ - onAbort?: () => void; + onAbort?: () => void /** * Whether a change in deps will cancel a queued request and make a new one */ - cancelOnChange?: boolean; + cancelOnChange?: boolean /** * Parse as json by default */ - resolver?: (d: CustomResponse) => any; + resolver?: (d: CustomResponse) => any /** * The ammount of attempts if request fails * @default 1 @@ -261,21 +265,21 @@ export type FetchConfigType = Omit< attempts?: | number | ((q: { - status: number; - res: Response; - error: Error; - completedAttempts: number; - }) => number | undefined | void); + status: number + res: Response + error: Error + completedAttempts: number + }) => number | undefined | void) /** * The interval at which to run attempts on request fail * @default 0 */ - attemptInterval?: TimeSpan; + attemptInterval?: TimeSpan /** * If a request should be made when the tab is focused. This currently works on browsers * @default false */ - revalidateOnFocus?: boolean; + revalidateOnFocus?: boolean /** * If `false`, revalidation will only happen when props passed to the `useFetch` change. * For example, you may want to have a component that should @@ -288,79 +292,79 @@ export type FetchConfigType = Omit< * Note that the behaviour when props change is the same. * @default true */ - revalidateOnMount?: boolean; + revalidateOnMount?: boolean /** * This will run when connection is interrupted */ - onOffline?: () => void; + onOffline?: () => void /** * This will run when connection is restored */ - onOnline?: (e: { cancel: () => void }) => void; + onOnline?: (e: { cancel: () => void }) => void /** * If the request should retry when connection is restored * @default true */ - retryOnReconnect?: boolean; + retryOnReconnect?: boolean /** * If using inside a `` */ - suspense?: boolean; + suspense?: boolean /** * Override base url */ - baseUrl?: string; + baseUrl?: string /** * Request method */ - method?: HTTP_METHODS; + method?: HTTP_METHODS /** * URL search params */ - query?: any; + query?: any /** * URL params */ - params?: any; + params?: any /** * Customize how body is formated for the request. By default it will be sent in JSON format * but you can set it to false if for example, you are sending a `FormData` * body, or to `b => serialize(b)` for example, if you want to send JSON data * (the last one is the default behaviour so in that case you can ignore it) */ - formatBody?: boolean | ((b: BodyType) => any); + formatBody?: boolean | ((b: BodyType) => any) /** * The time to wait before revalidation after props change */ - debounce?: TimeSpan; + debounce?: TimeSpan /** * Will run when the request is sent */ - onFetchStart?: FetchContextType["onFetchStart"]; + onFetchStart?: FetchContextType['onFetchStart'] /** * Will run when the response is received */ - onFetchEnd?: FetchContextType["onFetchEnd"]; + onFetchEnd?: FetchContextType['onFetchEnd'] /** * If `true`, the last resolved value be returned as `data` if the request fails. If `false`, the default value will be returned instead * * @default true */ - cacheIfError?: boolean; + cacheIfError?: boolean /** * The max age a page should be cached (with no request) */ - maxCacheAge?: TimeSpan; -}; + maxCacheAge?: TimeSpan +} // If first argument is a string export type FetchConfigTypeNoUrl = Omit< FetchConfigType, - "url" ->; + 'url' +> /** * Create a configuration object to use in a 'useFetche' call */ -export type FetchInit = FetchConfigType; +export type FetchInit = FetchConfigType diff --git a/src/utils/index.ts b/src/utils/index.ts index a1e4f7a..2d9cbf3 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,7 +1,7 @@ -"use client"; -import { useLayoutEffect, useEffect, useMemo } from "react"; -import { useGql } from "../hooks/others"; -import { useFetch } from "../hooks/use-fetch"; +'use client' +import { useLayoutEffect, useEffect, useMemo } from 'react' +import { useGql } from '../hooks/others' +import { useFetch } from '../hooks/use-fetch' import { abortControllers, @@ -11,10 +11,10 @@ import { requestInitialTimes, requestsProvider, runningMutate, - valuesMemory, -} from "../internal"; + valuesMemory +} from '../internal' -import { UNITS_MILISECONDS_EQUIVALENTS } from "../internal/constants"; +import { UNITS_MILISECONDS_EQUIVALENTS } from '../internal/constants' import { CacheStoreType, @@ -22,7 +22,9 @@ import { ImperativeFetch, FetchInit, TimeSpan, -} from "../types"; + FetchConfigTypeNoUrl, + FetchConfigType +} from '../types' import { gql, hasBaseUrl, @@ -30,156 +32,160 @@ import { isFunction, queue, serialize, - windowExists, -} from "./shared"; + windowExists +} from './shared' export function getMiliseconds(v: TimeSpan): number { - if (typeof v === "number") return v; + if (typeof v === 'number') return v - const [amount, unit] = (v as string).split(" "); + const [amount, unit] = (v as string).split(' ') - const amountNumber = parseFloat(amount); + const amountNumber = parseFloat(amount) if (!(unit in UNITS_MILISECONDS_EQUIVALENTS)) { - return amountNumber; + return amountNumber } // @ts-ignore - This should return the value in miliseconds - return amountNumber * UNITS_MILISECONDS_EQUIVALENTS[unit]; + return amountNumber * UNITS_MILISECONDS_EQUIVALENTS[unit] } export function getTimePassed(key: any) { return ( Date.now() - (isDefined(requestInitialTimes.get(key)) ? requestInitialTimes.get(key) : 0) - ); + ) } export const createImperativeFetch = (ctx: FetchContextType) => { const keys = [ - "GET", - "DELETE", - "HEAD", - "OPTIONS", - "POST", - "PUT", - "PATCH", - "PURGE", - "LINK", - "UNLINK", - ]; - - const { baseUrl } = ctx; + 'GET', + 'DELETE', + 'HEAD', + 'OPTIONS', + 'POST', + 'PUT', + 'PATCH', + 'PURGE', + 'LINK', + 'UNLINK' + ] + + const { baseUrl } = ctx return { ...Object.fromEntries( new Map( - keys.map((k) => [ + keys.map(k => [ k.toLowerCase(), (url, config = {}) => (useFetch as any)[k.toLowerCase()]( hasBaseUrl(url) ? url : baseUrl + url, { ...ctx, - ...config, + ...config } - ), + ) ]) ) ), - config: ctx, - } as ImperativeFetch; -}; + config: ctx + } as ImperativeFetch +} export const useIsomorphicLayoutEffect = windowExists ? useLayoutEffect - : useEffect; + : useEffect /** * Revalidate requests that match an id or ids */ export function revalidate(id: any | any[], __reval__ = true) { if (Array.isArray(id)) { - id.map((reqId) => { + id.map(reqId => { if (isDefined(reqId)) { - const key = serialize(reqId); + const key = serialize(reqId) - const resolveKey = serialize({ idString: key }); + const resolveKey = serialize({ idString: key }) if (__reval__) { - previousConfig.set(resolveKey, undefined); + previousConfig.set(resolveKey, undefined) } - abortControllers.get(resolveKey)?.abort(); + abortControllers.get(resolveKey)?.abort() if (__reval__) { if (!isPending(key)) { queue(() => { requestsProvider.emit(key, { loading: true, - error: false, - }); - }); + error: false + }) + }) } } } - }); + }) } else { if (isDefined(id)) { - const key = serialize(id); + const key = serialize(id) - const resolveKey = serialize({ idString: key }); + const resolveKey = serialize({ idString: key }) if (__reval__) { - previousConfig.set(resolveKey, undefined); + previousConfig.set(resolveKey, undefined) } - abortControllers.get(resolveKey)?.abort(); + abortControllers.get(resolveKey)?.abort() if (__reval__) { if (!isPending(key)) { queue(() => { requestsProvider.emit(key, { loading: true, - error: false, - }); - }); + error: false + }) + }) } } } } } +export function revalidateKey(key: any) { + revalidate([key]) +} + export function cancelRequest(id: any | any[]) { if (Array.isArray(id)) { - id.map((reqId) => { + id.map(reqId => { if (isDefined(reqId)) { const key = serialize({ - idString: serialize(reqId), - }); + idString: serialize(reqId) + }) if (isPending(key)) { - revalidate(reqId, false); + revalidate(reqId, false) queue(() => { requestsProvider.emit(key, { loading: false, - error: false, - }); - }); + error: false + }) + }) } } - }); + }) } else { if (isDefined(id)) { const key = serialize({ - idString: serialize(id), - }); + idString: serialize(id) + }) if (isPending(key)) { - revalidate(id, false); + revalidate(id, false) queue(() => { requestsProvider.emit(key, { loading: false, - error: false, - }); - }); + error: false + }) + }) } } } @@ -192,63 +198,63 @@ export function cancelRequest(id: any | any[]) { */ export function queryProvider( queries: { - [e in keyof R]: R[e]; + [e in keyof R]: R[e] }, providerConfig?: { defaults?: { - [key in keyof R]?: Partial>["value"]>; - }; + [key in keyof R]?: Partial>['value']> + } config?: { /** * The base url */ - baseUrl?: string; + baseUrl?: string /** * Any aditional headers */ headers?: { - [key: string]: any; - }; + [key: string]: any + } /** * The caching mechanism */ - cacheProvider?: CacheStoreType; - }; + cacheProvider?: CacheStoreType + } } ) { - type QuerysType = typeof queries; + type QuerysType = typeof queries return function useQuery

( queryName: P, otherConfig?: Omit< FetchInit< QuerysType[P] extends ReturnType - ? QuerysType[P]["value"] + ? QuerysType[P]['value'] : any >, - "url" + 'url' > & { default?: QuerysType[P] extends ReturnType - ? QuerysType[P]["value"] - : any; + ? QuerysType[P]['value'] + : any variables?: QuerysType[P] extends ReturnType - ? QuerysType[P]["variables"] - : any; - graphqlPath?: string; + ? QuerysType[P]['variables'] + : any + graphqlPath?: string } ) { - const { defaults } = providerConfig || {}; + const { defaults } = providerConfig || {} - const thisDefaults = (defaults || ({} as any))?.[queryName]; + const thisDefaults = (defaults || ({} as any))?.[queryName] const queryVariables = { ...thisDefaults?.variables, - ...(otherConfig as any)?.variables, - }; + ...(otherConfig as any)?.variables + } - const { config = {} } = providerConfig || {}; + const { config = {} } = providerConfig || {} - const { cacheProvider, ...others } = config; + const { cacheProvider, ...others } = config const g = useGql(queries[queryName] as any, { cacheProvider: config?.cacheProvider, @@ -270,7 +276,7 @@ export function queryProvider( headers: { ...others?.headers, ...thisDefaults?.headers, - ...otherConfig?.headers, + ...otherConfig?.headers }, ...{ __fromProvider: true }, default: { @@ -281,38 +287,38 @@ export function queryProvider( * 'value' property (when using the `gql` function) */ // @ts-ignore - otherConfig?.default) as R[P]["value"], + otherConfig?.default) as R[P]['value'] }, - variables: queryVariables, - }); + variables: queryVariables + }) const thisData = useMemo( () => ({ ...g?.data, - variables: queryVariables, + variables: queryVariables }), [serialize({ data: g?.data, queryVariables })] - ); + ) return { ...g, config: { ...g?.config, - config: undefined, + config: undefined }, - data: thisData, - } as Omit & { + data: thisData + } as Omit & { data: { data: QuerysType[P] extends ReturnType - ? QuerysType[P]["value"] - : any; - errors?: any[]; + ? QuerysType[P]['value'] + : any + errors?: any[] variables: QuerysType[P] extends ReturnType - ? QuerysType[P]["variables"] - : any; - }; - }; - }; + ? QuerysType[P]['variables'] + : any + } + } + } } /** @@ -323,45 +329,50 @@ export function mutateData( ) { for (let pair of pairs) { try { - const [k, v, _revalidate] = pair; - const key = serialize({ idString: serialize(k) }); - const requestCallId = ""; + const [k, v, _revalidate] = pair + const key = serialize({ idString: serialize(k) }) + const requestCallId = '' if (isFunction(v)) { - let newVal = v(cacheForMutation.get(key)); - runningMutate.set(key, undefined); + let newVal = v(cacheForMutation.get(key)) + runningMutate.set(key, undefined) requestsProvider.emit(key, { data: newVal, isMutating: true, - requestCallId, - }); + requestCallId + }) if (_revalidate) { - previousConfig.set(key, undefined); - requestsProvider.emit(serialize(k), {}); + previousConfig.set(key, undefined) + requestsProvider.emit(serialize(k), {}) } queue(() => { - valuesMemory.set(key, newVal); - cacheForMutation.set(key, newVal); - }); + valuesMemory.set(key, newVal) + cacheForMutation.set(key, newVal) + }) } else { - runningMutate.set(key, undefined); + runningMutate.set(key, undefined) requestsProvider.emit(key, { requestCallId, isMutating: true, - data: v, - }); + data: v + }) if (_revalidate) { - previousConfig.set(key, undefined); - requestsProvider.emit(serialize(k), {}); + previousConfig.set(key, undefined) + requestsProvider.emit(serialize(k), {}) } queue(() => { - valuesMemory.set(key, v); - cacheForMutation.set(key, v); - }); + valuesMemory.set(key, v) + cacheForMutation.set(key, v) + }) } } catch (err) {} } } -export function fetchOptions(options: FetchInit) { - return options; +export function fetchOptions( + init: string | FetchConfigType, + options?: Omit, 'url'> +) { + return typeof init === 'string' + ? { url: init, ...options } + : (init as FetchConfigType) }