@better-typed/react-hyper-fetch
Advanced tools
Comparing version 0.8.0 to 0.9.0
@@ -22,10 +22,18 @@ import { startServer, resetInterceptors, stopServer } from "../../server"; | ||
describe("when getting the response", () => { | ||
it("should trigger onCacheSuccess helper", async () => {}); | ||
it("should trigger onCacheError helper", async () => {}); | ||
it("should trigger onCacheUpdate helper", async () => {}); | ||
it("should trigger onCacheSuccess helper", async () => { | ||
// Todo | ||
}); | ||
it("should trigger onCacheError helper", async () => { | ||
// Todo | ||
}); | ||
it("should trigger onCacheUpdate helper", async () => { | ||
// Todo | ||
}); | ||
}); | ||
describe("when revalidate gets triggered", () => { | ||
it("should remove cached data", async () => {}); | ||
it("should remove cached data", async () => { | ||
// Todo | ||
}); | ||
}); | ||
}); | ||
}); |
import { act } from "@testing-library/react"; | ||
import { createCommand, renderUseFetch, createCacheData, waitForRender, builder } from "../../utils"; | ||
import { createCommand, renderUseFetch, createCacheData, builder } from "../../utils"; | ||
import { startServer, resetInterceptors, stopServer, createRequestInterceptor } from "../../server"; | ||
@@ -35,3 +35,2 @@ import { testSuccessState, testErrorState, testInitialState, testCacheState, testBuilderIsolation } from "../../shared"; | ||
testInitialState(view); | ||
await waitForRender(); | ||
}); | ||
@@ -46,3 +45,2 @@ it("should load cached data", async () => { | ||
const view = renderUseFetch(command); | ||
await waitForRender(); | ||
await testCacheState(cache, view); | ||
@@ -52,3 +50,3 @@ }); | ||
await testBuilderIsolation(builder); | ||
const timestamp = new Date(+new Date() - 11); | ||
const timestamp = +new Date() - 11; | ||
const mock = createRequestInterceptor(command, { delay: 20 }); | ||
@@ -59,3 +57,2 @@ createCacheData(command, { data: [mock, null, 200], details: { timestamp, retries: 3 } }); | ||
await waitForRender(); | ||
await testCacheState([null, null, null], view); | ||
@@ -70,3 +67,9 @@ }); | ||
it("should make only one request", async () => { | ||
// Todo | ||
const spy = jest.spyOn(builder.fetchDispatcher, "add"); | ||
await testBuilderIsolation(builder); | ||
const mock = createRequestInterceptor(command); | ||
const view = renderUseFetch(command); | ||
await testSuccessState(mock, view); | ||
expect(spy).toBeCalledTimes(1); | ||
}); | ||
@@ -80,3 +83,2 @@ }); | ||
await waitForRender(); | ||
await testSuccessState(mock, view); | ||
@@ -89,3 +91,2 @@ }); | ||
await waitForRender(); | ||
await testErrorState(errorMock, view); | ||
@@ -110,3 +111,2 @@ const mock = createRequestInterceptor(command); | ||
await waitForRender(); | ||
await testErrorState(mock, view); | ||
@@ -119,3 +119,2 @@ }); | ||
await waitForRender(); | ||
await testSuccessState(mock, view); | ||
@@ -122,0 +121,0 @@ |
@@ -6,3 +6,3 @@ import { startServer, resetInterceptors, stopServer, createRequestInterceptor } from "../../server"; | ||
describe("useFetch [ Deduplication ]", () => { | ||
let dedupeCommand = createCommand({ deduplicate: true, deduplicateTime: 20, retry: 5, retryTime: 200 }); | ||
let dedupeCommand = createCommand({ deduplicate: true, deduplicateTime: 30, retry: 5, retryTime: 200 }); | ||
@@ -22,3 +22,3 @@ beforeAll(() => { | ||
beforeEach(() => { | ||
dedupeCommand = createCommand({ deduplicate: true, deduplicateTime: 20, retry: 5, retryTime: 200 }); | ||
dedupeCommand = createCommand({ deduplicate: true, deduplicateTime: 30, retry: 5, retryTime: 200 }); | ||
jest.resetModules(); | ||
@@ -25,0 +25,0 @@ builder.clear(); |
@@ -22,12 +22,24 @@ import { startServer, resetInterceptors, stopServer } from "../../server"; | ||
describe("when stop gets triggered", () => { | ||
it("should cancel ongoing requests", async () => {}); | ||
it("should change stopped value", async () => {}); | ||
it("should cancel ongoing requests", async () => { | ||
// Todo | ||
}); | ||
it("should change stopped value", async () => { | ||
// Todo | ||
}); | ||
}); | ||
describe("when pause gets triggered", () => { | ||
it("should finish ongoing requests", async () => {}); | ||
it("should change stopped value", async () => {}); | ||
it("should finish ongoing requests", async () => { | ||
// Todo | ||
}); | ||
it("should change stopped value", async () => { | ||
// Todo | ||
}); | ||
}); | ||
describe("when stopping request", () => { | ||
it("should cancel request and mark it as stopped", async () => {}); | ||
it("should take another requests and trigger them", async () => {}); | ||
it("should cancel request and mark it as stopped", async () => { | ||
// Todo | ||
}); | ||
it("should take another requests and trigger them", async () => { | ||
// Todo | ||
}); | ||
}); | ||
@@ -38,9 +50,15 @@ }); | ||
describe("when start gets triggered", () => { | ||
it("should send all queued requests", async () => {}); | ||
it("should not send stopped requests", async () => {}); | ||
it("should send all queued requests", async () => { | ||
// Todo | ||
}); | ||
it("should not send stopped requests", async () => { | ||
// Todo | ||
}); | ||
}); | ||
describe("when starting request", () => { | ||
it("should not send a request", async () => {}); | ||
it("should not send a request", async () => { | ||
// Todo | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -25,3 +25,3 @@ import { | ||
const timeoutTime = command.options?.timeout || command.builder?.requestConfig?.timeout || defaultTimeout; | ||
const timeoutTime = command.options?.timeout || defaultTimeout; | ||
const isTimeout = timeoutTime < delay; | ||
@@ -28,0 +28,0 @@ |
import { waitFor, RenderHookResult } from "@testing-library/react"; | ||
import { ClientResponseType, ExtractResponse, CommandInstance } from "@better-typed/hyper-fetch"; | ||
import { ClientResponseType, CommandInstance } from "@better-typed/hyper-fetch"; | ||
@@ -21,3 +21,3 @@ import { UseFetchReturnType } from "use-fetch"; | ||
export const testSuccessState = async < | ||
T extends UseFetchReturnType<CommandInstance> | UseSubmitReturnType<T>, | ||
T extends UseFetchReturnType<CommandInstance> | UseSubmitReturnType<CommandInstance>, | ||
H extends RenderHookResult<any, any>, | ||
@@ -48,3 +48,3 @@ >( | ||
render: H, | ||
data: ExtractResponse<T> | null = null, | ||
data: any | null = null, | ||
) => { | ||
@@ -78,9 +78,3 @@ await waitFor(() => { | ||
export const testLoading = async < | ||
T extends UseFetchReturnType<CommandInstance> | UseSubmitReturnType<T>, | ||
H extends RenderHookResult<any, any>, | ||
>( | ||
mock: boolean, | ||
render: H, | ||
) => { | ||
export const testLoading = async <H extends RenderHookResult<any, any>>(mock: boolean, render: H) => { | ||
await waitFor(() => { | ||
@@ -97,3 +91,3 @@ const response = getCurrentState(render); | ||
export const testData = async < | ||
T extends UseFetchReturnType<CommandInstance> | UseSubmitReturnType<T>, | ||
T extends UseFetchReturnType<CommandInstance> | UseSubmitReturnType<CommandInstance>, | ||
H extends RenderHookResult<any, any>, | ||
@@ -111,3 +105,3 @@ >( | ||
export const testError = async < | ||
T extends UseFetchReturnType<CommandInstance> | UseSubmitReturnType<T>, | ||
T extends UseFetchReturnType<CommandInstance> | UseSubmitReturnType<CommandInstance>, | ||
H extends RenderHookResult<any, any>, | ||
@@ -114,0 +108,0 @@ >( |
@@ -9,1 +9,3 @@ export * from "./builder.utils"; | ||
export * from "./use-submit.utils"; | ||
export * from "./use-app-manager.utils"; | ||
export * from "./use-queue.utils"; |
export * from "./use-command-events"; | ||
export * from "./use-debounce"; | ||
export * from "./use-dependent-state"; | ||
export * from "./use-tracked-state"; |
@@ -1,2 +0,3 @@ | ||
import { UseCommandEventsReturnType, UseCommandEventsOptionsType } from "helpers"; | ||
import { CommandInstance } from "@better-typed/hyper-fetch"; | ||
import { UseCommandEventsReturnType, UseCommandEventsOptionsType } from "./.."; | ||
/** | ||
@@ -8,2 +9,2 @@ * This is helper hook that handles main Hyper-Fetch event/data flow | ||
*/ | ||
export declare const useCommandEvents: <T extends Command<any, any, any, any, any, any, any, any, any, any, any>>({ command, dispatcher, logger, state, actions, setCacheData, initializeCallbacks, }: UseCommandEventsOptionsType<T>) => UseCommandEventsReturnType<T>; | ||
export declare const useCommandEvents: <T extends CommandInstance>({ command, dispatcher, logger, actions, setCacheData, }: UseCommandEventsOptionsType<T>) => UseCommandEventsReturnType<T>; |
@@ -1,3 +0,3 @@ | ||
import { Dispatcher, ExtractError, CacheValueType, ExtractResponse, LoggerMethodsType, FetchProgressType, ExtractFetchReturn, CommandEventDetails, CommandInstance, CommandResponseDetails } from "@better-typed/hyper-fetch"; | ||
import { UseDependentStateType, UseDependentStateActions } from "helpers"; | ||
import { Dispatcher, ExtractError, CacheValueType, ExtractResponse, LoggerType, FetchProgressType, ExtractClientReturnType, CommandEventDetails, CommandInstance, CommandResponseDetails } from "@better-typed/hyper-fetch"; | ||
import { UseTrackedStateActions } from "./.."; | ||
export declare type UseCommandEventsDataMap = { | ||
@@ -12,22 +12,51 @@ unmount: VoidFunction; | ||
dispatcher: Dispatcher; | ||
logger: LoggerMethodsType; | ||
state: UseDependentStateType<T>; | ||
actions: UseDependentStateActions<T>; | ||
logger: LoggerType; | ||
actions: UseTrackedStateActions<T>; | ||
setCacheData: (cacheData: CacheValueType<ExtractResponse<T>, ExtractError<T>>) => void; | ||
initializeCallbacks?: boolean; | ||
}; | ||
export declare type UseCommandEventsActionsType<T extends CommandInstance> = { | ||
/** | ||
* Callback which allows to cancel ongoing requests from given queueKey. | ||
*/ | ||
abort: () => void; | ||
/** | ||
* Helper hook listening on success response. | ||
*/ | ||
onSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on error response. | ||
*/ | ||
onError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on aborting of requests. Abort events are not triggering onError callbacks. | ||
*/ | ||
onAbort: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on request going into offline awaiting for network connection to be restored. It will not trigger onError when 'offline' mode is set on command. | ||
*/ | ||
onOfflineError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on any response. | ||
*/ | ||
onFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on request start. | ||
*/ | ||
onRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on response start(before we receive all data from server). | ||
*/ | ||
onResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on download progress ETA. We can later match given requests by their id's or command instance which holds all data which is being transferred. | ||
*/ | ||
onDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
/** | ||
* Helper hook listening on upload progress ETA. We can later match given requests by their id's or command instance which holds all data which is being transferred. | ||
*/ | ||
onUploadProgress: (callback: OnProgressCallbackType) => void; | ||
}; | ||
export declare type UseCommandEventsReturnType<T extends CommandInstance> = [ | ||
UseCommandEventsActionsType<T>, | ||
{ | ||
abort: () => void; | ||
onSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
onError: (callback: OnErrorCallbackType<T>) => void; | ||
onAbort: (callback: OnErrorCallbackType<T>) => void; | ||
onOfflineError: (callback: OnErrorCallbackType<T>) => void; | ||
onFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
onRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
onResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
onDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
onUploadProgress: (callback: OnProgressCallbackType) => void; | ||
}, | ||
{ | ||
addDataListener: (command: CommandInstance) => VoidFunction; | ||
@@ -47,3 +76,3 @@ clearDataListener: VoidFunction; | ||
export declare type OnErrorCallbackType<Command extends CommandInstance> = (params: CallbackParameters<Command, ExtractError<Command>>) => void; | ||
export declare type OnFinishedCallbackType<Command extends CommandInstance> = (params: CallbackParameters<Command, ExtractFetchReturn<Command>>) => void; | ||
export declare type OnFinishedCallbackType<Command extends CommandInstance> = (params: CallbackParameters<Command, ExtractClientReturnType<Command>>) => void; | ||
export declare type OnStartCallbackType<Command extends CommandInstance> = (params: { | ||
@@ -53,2 +82,2 @@ details: CommandEventDetails<Command>; | ||
}) => void; | ||
export declare type OnProgressCallbackType = (progress: FetchProgressType) => void; | ||
export declare type OnProgressCallbackType = <Command extends CommandInstance>(progress: FetchProgressType, details: CommandEventDetails<Command>) => void; |
@@ -1,1078 +0,2 @@ | ||
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 __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 __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, { | ||
getDetailsState: () => getDetailsState, | ||
getInitialState: () => getInitialState, | ||
getTimestamp: () => getTimestamp, | ||
getValidCacheData: () => getValidCacheData, | ||
initialState: () => initialState, | ||
isEmpty: () => isEmpty, | ||
isEqual: () => isEqual, | ||
isStaleCacheData: () => isStaleCacheData, | ||
responseToCacheValue: () => responseToCacheValue, | ||
useAppManager: () => useAppManager, | ||
useCache: () => useCache, | ||
useCacheDefaultOptions: () => useCacheDefaultOptions, | ||
useCommandEvents: () => useCommandEvents, | ||
useDebounce: () => useDebounce, | ||
useDependentState: () => useDependentState, | ||
useFetch: () => useFetch, | ||
useFetchDefaultOptions: () => useFetchDefaultOptions, | ||
useQueue: () => useQueue, | ||
useQueueDefaultOptions: () => useQueueDefaultOptions, | ||
useSubmit: () => useSubmit, | ||
useSubmitDefaultOptions: () => useSubmitDefaultOptions | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
// src/use-fetch/use-fetch.hooks.ts | ||
var import_react4 = require("react"); | ||
var import_react_lifecycle_hooks4 = require("@better-typed/react-lifecycle-hooks"); | ||
var import_hyper_fetch2 = require("@better-typed/hyper-fetch"); | ||
// src/helpers/use-command-events/use-command-events.hooks.ts | ||
var import_react = require("react"); | ||
var import_hyper_fetch = require("@better-typed/hyper-fetch"); | ||
var import_react_lifecycle_hooks = require("@better-typed/react-lifecycle-hooks"); | ||
var useCommandEvents = ({ | ||
command, | ||
dispatcher, | ||
logger, | ||
state, | ||
actions, | ||
setCacheData, | ||
initializeCallbacks = false | ||
}) => { | ||
const { cache, appManager, commandManager } = command.builder; | ||
const commandDump = command.dump(); | ||
const isMounted = (0, import_react_lifecycle_hooks.useIsMounted)(); | ||
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, data, details) => { | ||
var _a, _b, _c, _d, _e; | ||
if (!isMounted) | ||
return logger.debug("Callback cancelled, component is unmounted"); | ||
const { isOffline, isFailed, isCanceled } = details; | ||
if (command.offline && isOffline && isFailed) { | ||
logger.debug("Performing offline error callback", { data, details }); | ||
(_a = onOfflineErrorCallback.current) == null ? void 0 : _a.call(onOfflineErrorCallback, { response: data[1], command: cmd, details }); | ||
} else if (isCanceled) { | ||
logger.debug("Performing abort callback", { data, details }); | ||
(_b = onAbortCallback.current) == null ? void 0 : _b.call(onAbortCallback, { response: data[1], command: cmd, details }); | ||
} else if (!isFailed) { | ||
logger.debug("Performing success callback", { data, details }); | ||
(_c = onSuccessCallback.current) == null ? void 0 : _c.call(onSuccessCallback, { response: data[0], command: cmd, details }); | ||
} else { | ||
logger.debug("Performing error callback", { data, details }); | ||
(_d = onErrorCallback.current) == null ? void 0 : _d.call(onErrorCallback, { response: data[1], command: cmd, details }); | ||
} | ||
(_e = onFinishedCallback.current) == null ? void 0 : _e.call(onFinishedCallback, { response: data, command: cmd, details }); | ||
}; | ||
const handleInitialCallbacks = () => { | ||
const hasData = state.data && state.error && state.timestamp; | ||
if (hasData && initializeCallbacks) { | ||
const details = { | ||
retries: state.retries, | ||
timestamp: new Date(state.timestamp), | ||
isFailed: (0, import_hyper_fetch.isFailedRequest)([state.data, state.error, state.status]), | ||
isCanceled: false, | ||
isOffline: !appManager.isOnline | ||
}; | ||
handleResponseCallbacks(command, [state.data, state.error, state.status], details); | ||
} | ||
}; | ||
const handleGetLoadingEvent = (queueKey) => { | ||
return ({ isLoading }) => { | ||
const canDisableLoading = !isLoading && !dispatcher.hasRunningRequests(queueKey); | ||
if (isLoading || canDisableLoading) { | ||
actions.setLoading(isLoading, false); | ||
} | ||
}; | ||
}; | ||
const handleDownloadProgress = (progress) => { | ||
var _a; | ||
(_a = onDownloadProgressCallback == null ? void 0 : onDownloadProgressCallback.current) == null ? void 0 : _a.call(onDownloadProgressCallback, progress); | ||
}; | ||
const handleUploadProgress = (progress) => { | ||
var _a; | ||
(_a = onUploadProgressCallback == null ? void 0 : onUploadProgressCallback.current) == null ? void 0 : _a.call(onUploadProgressCallback, progress); | ||
}; | ||
const handleRequestStart = (cmd) => { | ||
return (details) => { | ||
var _a; | ||
(_a = onRequestStartCallback == null ? void 0 : onRequestStartCallback.current) == null ? void 0 : _a.call(onRequestStartCallback, { command: cmd, details }); | ||
}; | ||
}; | ||
const handleResponseStart = (cmd) => { | ||
return (details) => { | ||
var _a; | ||
(_a = onResponseStartCallback == null ? void 0 : onResponseStartCallback.current) == null ? void 0 : _a.call(onResponseStartCallback, { command: cmd, details }); | ||
}; | ||
}; | ||
const handleResponse = (cmd) => { | ||
return (data, details) => { | ||
handleResponseCallbacks(cmd, data, details); | ||
}; | ||
}; | ||
const handleRemove = (requestId) => { | ||
removeLifecycleListener(requestId); | ||
}; | ||
const handleAbort = (cmd) => { | ||
return () => { | ||
const data = [ | ||
null, | ||
(0, import_hyper_fetch.getErrorMessage)("abort"), | ||
0 | ||
]; | ||
const details = { | ||
retries: 0, | ||
timestamp: new Date(), | ||
isFailed: false, | ||
isCanceled: true, | ||
isOffline: false | ||
}; | ||
handleResponseCallbacks(cmd, data, details); | ||
}; | ||
}; | ||
const clearDataListener = () => { | ||
var _a; | ||
(_a = dataEvents.current) == null ? void 0 : _a.unmount(); | ||
dataEvents.current = null; | ||
}; | ||
const addDataListener = (cmd) => { | ||
const loadingUnmount = commandManager.events.onLoading(cmd.queueKey, handleGetLoadingEvent(cmd.queueKey)); | ||
const getResponseUnmount = cache.events.get(cmd.cacheKey, setCacheData); | ||
const abortUnmount = commandManager.events.onAbort(cmd.abortKey, handleAbort(cmd)); | ||
const unmount = () => { | ||
loadingUnmount(); | ||
getResponseUnmount(); | ||
abortUnmount(); | ||
}; | ||
clearDataListener(); | ||
dataEvents.current = { unmount }; | ||
return unmount; | ||
}; | ||
const addLifecycleListeners = (cmd, requestId) => { | ||
if (!requestId) { | ||
const { queueKey, cacheKey } = cmd; | ||
const requestStartUnmount2 = commandManager.events.onRequestStart(queueKey, handleRequestStart(cmd)); | ||
const responseStartUnmount2 = commandManager.events.onResponseStart(queueKey, handleResponseStart(cmd)); | ||
const uploadUnmount2 = commandManager.events.onUploadProgress(queueKey, handleUploadProgress); | ||
const downloadUnmount2 = commandManager.events.onDownloadProgress(queueKey, handleDownloadProgress); | ||
const responseUnmount2 = commandManager.events.onResponse(cacheKey, handleResponse(cmd)); | ||
const unmount2 = () => { | ||
downloadUnmount2(); | ||
uploadUnmount2(); | ||
requestStartUnmount2(); | ||
responseStartUnmount2(); | ||
responseUnmount2(); | ||
}; | ||
lifecycleEvents.current.set(queueKey, { unmount: unmount2 }); | ||
return unmount2; | ||
} | ||
const requestRemove = commandManager.events.onRemoveById(requestId, handleRemove); | ||
const requestStartUnmount = commandManager.events.onRequestStartById(requestId, handleRequestStart(cmd)); | ||
const responseStartUnmount = commandManager.events.onResponseStartById(requestId, handleResponseStart(cmd)); | ||
const responseUnmount = commandManager.events.onResponseById(requestId, handleResponse(cmd)); | ||
const uploadUnmount = commandManager.events.onUploadProgressById(requestId, handleUploadProgress); | ||
const downloadUnmount = commandManager.events.onDownloadProgressById(requestId, handleDownloadProgress); | ||
const unmount = () => { | ||
requestRemove(); | ||
downloadUnmount(); | ||
uploadUnmount(); | ||
requestStartUnmount(); | ||
responseStartUnmount(); | ||
responseUnmount(); | ||
}; | ||
lifecycleEvents.current.set(requestId, { unmount }); | ||
return unmount; | ||
}; | ||
const abort = () => { | ||
const { abortKey } = command; | ||
const requests = dispatcher.getAllRunningRequest(); | ||
requests.forEach((request) => { | ||
if (request.command.abortKey === abortKey) { | ||
dispatcher.delete(request.command.queueKey, request.requestId, abortKey); | ||
} | ||
}); | ||
}; | ||
(0, import_react_lifecycle_hooks.useDidUpdate)(handleInitialCallbacks, [commandDump.cacheKey, commandDump.queueKey], true); | ||
(0, import_react_lifecycle_hooks.useWillUnmount)(() => { | ||
clearLifecycleListeners(); | ||
clearDataListener(); | ||
}); | ||
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; | ||
} | ||
}, | ||
{ | ||
addDataListener, | ||
clearDataListener, | ||
addLifecycleListeners, | ||
removeLifecycleListener, | ||
clearLifecycleListeners | ||
} | ||
]; | ||
}; | ||
// src/helpers/use-debounce/use-debounce.hooks.ts | ||
var import_react2 = require("react"); | ||
var import_react_lifecycle_hooks2 = require("@better-typed/react-lifecycle-hooks"); | ||
var useDebounce = (delay = 600) => { | ||
const debounce = (0, import_react2.useRef)({ | ||
time: delay, | ||
timer: null | ||
}); | ||
(0, import_react_lifecycle_hooks2.useDidUpdate)(() => { | ||
debounce.current.time = delay; | ||
}, [delay]); | ||
const resetDebounce = () => { | ||
if (debounce.current.timer !== null) | ||
clearTimeout(debounce.current.timer); | ||
debounce.current.timer = null; | ||
}; | ||
const setDebounce = (callback, time) => { | ||
resetDebounce(); | ||
debounce.current.timer = setTimeout(() => { | ||
callback(); | ||
}, time || debounce.current.time); | ||
}; | ||
(0, import_react_lifecycle_hooks2.useWillUnmount)(resetDebounce); | ||
return { debounce: setDebounce, resetDebounce, active: !!debounce.current.timer }; | ||
}; | ||
// src/helpers/use-dependent-state/use-dependent-state.constants.ts | ||
var initialState = { | ||
data: null, | ||
error: null, | ||
loading: false, | ||
status: null, | ||
retries: 0, | ||
timestamp: null | ||
}; | ||
// src/helpers/use-dependent-state/use-dependent-state.hooks.ts | ||
var import_react3 = require("react"); | ||
var import_react_lifecycle_hooks3 = require("@better-typed/react-lifecycle-hooks"); | ||
// 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) => { | ||
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; | ||
}; | ||
// src/helpers/use-dependent-state/use-dependent-state.utils.ts | ||
var getDetailsState = (state, details) => { | ||
return __spreadValues({ | ||
retries: (state == null ? void 0 : state.retries) || 0, | ||
timestamp: new Date(), | ||
isFailed: false, | ||
isCanceled: false, | ||
isOffline: false | ||
}, details); | ||
}; | ||
var isStaleCacheData = (cacheTime, cacheTimestamp) => { | ||
if (!cacheTimestamp) | ||
return true; | ||
if (!cacheTime) | ||
return false; | ||
return +new Date() > +cacheTimestamp + cacheTime; | ||
}; | ||
var getValidCacheData = (command, initialData, cacheData) => { | ||
const isStale = isStaleCacheData(command.cacheTime, cacheData == null ? void 0 : cacheData.details.timestamp); | ||
if (!isStale && cacheData) { | ||
return cacheData; | ||
} | ||
if (initialData) { | ||
return { | ||
data: initialData, | ||
details: getDetailsState(), | ||
cacheTime: 1e3 | ||
}; | ||
} | ||
return null; | ||
}; | ||
var getTimestamp = (timestamp) => { | ||
return timestamp ? new Date(timestamp) : null; | ||
}; | ||
var responseToCacheValue = (response) => { | ||
if (!response) | ||
return null; | ||
return { | ||
data: response, | ||
details: getDetailsState(), | ||
cacheTime: 1e3 | ||
}; | ||
}; | ||
var getInitialState = (initialData, dispatcher, command) => { | ||
var _a, _b, _c; | ||
const { builder, cacheKey } = command; | ||
const { cache } = builder; | ||
const cacheData = cache.get(cacheKey); | ||
const cacheState = getValidCacheData(command, initialData, cacheData); | ||
const initialLoading = dispatcher.hasRunningRequests(command.queueKey); | ||
return __spreadProps(__spreadValues({}, initialState), { | ||
data: ((_a = cacheState == null ? void 0 : cacheState.data) == null ? void 0 : _a[0]) || initialState.data, | ||
error: ((_b = cacheState == null ? void 0 : cacheState.data) == null ? void 0 : _b[1]) || initialState.error, | ||
status: ((_c = cacheState == null ? void 0 : cacheState.data) == null ? void 0 : _c[2]) || initialState.status, | ||
retries: (cacheState == null ? void 0 : cacheState.details.retries) || initialState.retries, | ||
timestamp: getTimestamp((cacheState == null ? void 0 : cacheState.details.timestamp) || initialState.timestamp), | ||
loading: initialLoading != null ? initialLoading : initialState.loading | ||
}); | ||
}; | ||
// src/helpers/use-dependent-state/use-dependent-state.hooks.ts | ||
var useDependentState = ({ | ||
command, | ||
dispatcher, | ||
initialData, | ||
deepCompare, | ||
dependencyTracking, | ||
defaultCacheEmitting = true | ||
}) => { | ||
const { builder, cacheKey, queueKey, cacheTime } = command; | ||
const { cache, commandManager } = builder; | ||
const forceUpdate = (0, import_react_lifecycle_hooks3.useForceUpdate)(); | ||
const state = (0, import_react3.useRef)(getInitialState(initialData, dispatcher, command)); | ||
const renderKeys = (0, import_react3.useRef)([]); | ||
const getStaleStatus = () => { | ||
const cacheData = cache.get(cacheKey); | ||
return isStaleCacheData(cacheTime, cacheData == null ? void 0 : cacheData.details.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_react_lifecycle_hooks3.useDidUpdate)(() => { | ||
state.current.loading = dispatcher.hasRunningRequests(queueKey); | ||
const newState = getInitialState(initialData, dispatcher, command); | ||
const hasInitialState = (initialData == null ? void 0 : initialData[0]) === 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 (shouldLoadInitialCache || shouldRemovePreviousData) { | ||
state.current = newState; | ||
} | ||
}, [cacheKey, queueKey], true); | ||
(0, import_react_lifecycle_hooks3.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 setCacheData = (cacheData) => __async(void 0, null, function* () { | ||
const newStateValues = { | ||
data: cacheData.data[0], | ||
error: cacheData.data[1], | ||
status: cacheData.data[2], | ||
retries: cacheData.details.retries, | ||
timestamp: new Date(cacheData.details.timestamp), | ||
loading: state.current.loading | ||
}; | ||
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 actions = { | ||
setData: (data, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [data, currentState.error, currentState.status], getDetailsState(state.current)); | ||
} else { | ||
state.current.data = data; | ||
renderKeyTrigger(["data"]); | ||
} | ||
}, | ||
setError: (error, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [currentState.data, error, currentState.status], getDetailsState(state.current, { isFailed: !!error })); | ||
} else { | ||
state.current.error = error; | ||
renderKeyTrigger(["error"]); | ||
} | ||
}, | ||
setLoading: (loading, emitToHooks = true) => { | ||
if (emitToHooks) { | ||
commandManager.events.setLoading(queueKey, "", { | ||
isLoading: loading, | ||
isRetry: false, | ||
isOffline: false | ||
}); | ||
} else { | ||
state.current.loading = loading; | ||
renderKeyTrigger(["loading"]); | ||
} | ||
}, | ||
setStatus: (status, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [currentState.data, currentState.error, status], getDetailsState(state.current)); | ||
} else { | ||
state.current.status = status; | ||
renderKeyTrigger(["status"]); | ||
} | ||
}, | ||
setRetries: (retries, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [currentState.data, currentState.error, currentState.status], getDetailsState(state.current, { retries })); | ||
} else { | ||
state.current.retries = retries; | ||
renderKeyTrigger(["retries"]); | ||
} | ||
}, | ||
setTimestamp: (timestamp, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [currentState.data, currentState.error, currentState.status], getDetailsState(state.current, { timestamp })); | ||
} else { | ||
state.current.timestamp = timestamp; | ||
renderKeyTrigger(["timestamp"]); | ||
} | ||
} | ||
}; | ||
return [state.current, actions, { setRenderKey, setCacheData, getStaleStatus }]; | ||
}; | ||
// src/use-fetch/use-fetch.hooks.ts | ||
var useFetch = (command, { | ||
dependencies = useFetchDefaultOptions.dependencies, | ||
disabled = useFetchDefaultOptions.disabled, | ||
dependencyTracking = useFetchDefaultOptions.dependencyTracking, | ||
revalidateOnMount = useFetchDefaultOptions.revalidateOnMount, | ||
initialData = useFetchDefaultOptions.initialData, | ||
refresh = useFetchDefaultOptions.refresh, | ||
refreshTime = useFetchDefaultOptions.refreshTime, | ||
refreshBlurred = useFetchDefaultOptions.refreshBlurred, | ||
refreshOnTabBlur = useFetchDefaultOptions.refreshOnTabBlur, | ||
refreshOnTabFocus = useFetchDefaultOptions.refreshOnTabFocus, | ||
refreshOnReconnect = useFetchDefaultOptions.refreshOnReconnect, | ||
debounce = useFetchDefaultOptions.debounce, | ||
debounceTime = useFetchDefaultOptions.debounceTime, | ||
deepCompare = useFetchDefaultOptions.deepCompare | ||
} = useFetchDefaultOptions) => { | ||
const updateKey = JSON.stringify(command.dump()); | ||
const requestDebounce = useDebounce(debounceTime); | ||
const refreshDebounce = useDebounce(refreshTime); | ||
const { cacheKey, queueKey, builder } = command; | ||
const { cache, fetchDispatcher: dispatcher, appManager, loggerManager } = builder; | ||
const logger = (0, import_react4.useRef)(loggerManager.init("useFetch")).current; | ||
const [state, actions, { setRenderKey, setCacheData, getStaleStatus }] = useDependentState({ | ||
logger, | ||
command, | ||
dispatcher, | ||
initialData, | ||
deepCompare, | ||
dependencyTracking | ||
}); | ||
const [callbacks, listeners] = useCommandEvents({ | ||
state, | ||
logger, | ||
actions, | ||
command, | ||
dispatcher, | ||
setCacheData | ||
}); | ||
const { addDataListener, addLifecycleListeners, clearDataListener, clearLifecycleListeners } = listeners; | ||
const handleFetch = () => { | ||
if (!disabled) { | ||
logger.debug(`Adding request to fetch queue`); | ||
dispatcher.add(command); | ||
} else { | ||
logger.debug(`Cannot add to fetch queue`, { disabled }); | ||
} | ||
}; | ||
function handleRefresh() { | ||
if (!refresh) | ||
return; | ||
logger.debug(`Starting refresh counter, request will be send in ${refreshTime}ms`); | ||
refreshDebounce.debounce(() => { | ||
const isBlurred = !appManager.isFocused; | ||
const isFetching = dispatcher.hasRunningRequests(command.queueKey); | ||
const isQueued = dispatcher.getIsActiveQueue(command.queueKey); | ||
const isActive = isFetching || isQueued; | ||
const canRefreshBlurred = isBlurred && refreshBlurred && !isActive; | ||
const canRefreshFocused = !isBlurred && !isActive; | ||
if (canRefreshBlurred || canRefreshFocused) { | ||
handleFetch(); | ||
logger.debug(`Performing refresh request`); | ||
} | ||
handleRefresh(); | ||
}); | ||
} | ||
const revalidate = (invalidateKey) => { | ||
if (invalidateKey && invalidateKey instanceof import_hyper_fetch2.Command) { | ||
cache.events.revalidate((0, import_hyper_fetch2.getCommandKey)(invalidateKey)); | ||
} else if (invalidateKey) { | ||
cache.events.revalidate(invalidateKey); | ||
} else { | ||
handleFetch(); | ||
handleRefresh(); | ||
} | ||
}; | ||
const initialFetchData = () => { | ||
const hasStaleData = getStaleStatus(); | ||
if (revalidateOnMount || hasStaleData) { | ||
handleFetch(); | ||
} | ||
}; | ||
const updateFetchData = () => { | ||
if (debounce) { | ||
logger.debug("Debouncing request", { queueKey, command }); | ||
requestDebounce.debounce(() => handleFetch()); | ||
} else { | ||
handleFetch(); | ||
} | ||
}; | ||
const handleMountEvents = () => { | ||
addDataListener(command); | ||
addLifecycleListeners(command); | ||
const focusUnmount = appManager.events.onFocus(() => { | ||
if (refreshOnTabFocus) { | ||
handleFetch(); | ||
handleRefresh(); | ||
} | ||
}); | ||
const blurUnmount = appManager.events.onBlur(() => { | ||
if (refreshOnTabBlur) { | ||
handleFetch(); | ||
handleRefresh(); | ||
} | ||
}); | ||
const onlineUnmount = appManager.events.onOnline(() => { | ||
if (refreshOnReconnect) { | ||
handleFetch(); | ||
handleRefresh(); | ||
} | ||
}); | ||
const revalidateUnmount = cache.events.onRevalidate(cacheKey, handleFetch); | ||
const unmount = () => { | ||
clearDataListener(); | ||
clearLifecycleListeners(); | ||
focusUnmount(); | ||
blurUnmount(); | ||
onlineUnmount(); | ||
revalidateUnmount(); | ||
}; | ||
return unmount; | ||
}; | ||
(0, import_react_lifecycle_hooks4.useDidUpdate)(handleMountEvents, [updateKey], true); | ||
(0, import_react_lifecycle_hooks4.useDidMount)(initialFetchData); | ||
(0, import_react_lifecycle_hooks4.useDidUpdate)(updateFetchData, [updateKey, ...dependencies]); | ||
(0, import_react_lifecycle_hooks4.useDidUpdate)(handleRefresh, [updateKey, ...dependencies, disabled, refresh, refreshTime], 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 retries() { | ||
setRenderKey("retries"); | ||
return state.retries; | ||
}, | ||
get timestamp() { | ||
setRenderKey("timestamp"); | ||
return state.timestamp; | ||
} | ||
}, actions), callbacks), { | ||
isDebouncing: requestDebounce.active, | ||
revalidate | ||
}); | ||
}; | ||
// src/use-fetch/use-fetch.constants.ts | ||
var import_hyper_fetch3 = require("@better-typed/hyper-fetch"); | ||
var useFetchDefaultOptions = { | ||
dependencies: [], | ||
disabled: false, | ||
dependencyTracking: true, | ||
revalidateOnMount: true, | ||
initialData: null, | ||
refresh: false, | ||
refreshTime: import_hyper_fetch3.DateInterval.hour, | ||
refreshBlurred: true, | ||
refreshOnTabBlur: false, | ||
refreshOnTabFocus: false, | ||
refreshOnReconnect: false, | ||
debounce: false, | ||
debounceTime: 400, | ||
deepCompare: true | ||
}; | ||
// src/use-submit/use-submit.hooks.ts | ||
var import_react5 = require("react"); | ||
var import_hyper_fetch4 = require("@better-typed/hyper-fetch"); | ||
var import_react_lifecycle_hooks5 = require("@better-typed/react-lifecycle-hooks"); | ||
var useSubmit = (command, { | ||
disabled = useSubmitDefaultOptions.disabled, | ||
dependencyTracking = useSubmitDefaultOptions.dependencyTracking, | ||
initialData = useSubmitDefaultOptions.initialData, | ||
debounce = useSubmitDefaultOptions.debounce, | ||
debounceTime = useSubmitDefaultOptions.debounceTime, | ||
deepCompare = useSubmitDefaultOptions.deepCompare | ||
} = useSubmitDefaultOptions) => { | ||
const { builder } = command; | ||
const { cache, submitDispatcher: dispatcher, loggerManager } = builder; | ||
const logger = (0, import_react5.useRef)(loggerManager.init("useSubmit")).current; | ||
const requestDebounce = useDebounce(debounceTime); | ||
const [state, actions, { setRenderKey, setCacheData }] = useDependentState({ | ||
logger, | ||
command, | ||
dispatcher, | ||
initialData, | ||
deepCompare, | ||
dependencyTracking | ||
}); | ||
const [callbacks, listeners] = useCommandEvents({ | ||
state, | ||
logger, | ||
actions, | ||
command, | ||
dispatcher, | ||
setCacheData | ||
}); | ||
const { addDataListener, addLifecycleListeners } = listeners; | ||
const handleSubmit = (...parameters) => { | ||
const options = parameters[0]; | ||
const commandClone = command.clone(options); | ||
if (disabled) { | ||
logger.debug(`Cannot add to submit queue`, { disabled, options }); | ||
return [null, null, 0]; | ||
} | ||
const triggerRequest = () => { | ||
addDataListener(commandClone); | ||
return (0, import_hyper_fetch4.commandSendRequest)(commandClone, "submit", (requestId) => { | ||
addLifecycleListeners(commandClone, requestId); | ||
}); | ||
}; | ||
return new Promise((resolve) => { | ||
const performSubmit = () => __async(void 0, null, function* () { | ||
logger.debug(`Adding request to submit queue`, { disabled, options }); | ||
if (debounce) { | ||
requestDebounce.debounce(() => __async(void 0, null, function* () { | ||
const value = yield triggerRequest(); | ||
resolve(value); | ||
})); | ||
} else { | ||
const value = yield triggerRequest(); | ||
resolve(value); | ||
} | ||
}); | ||
performSubmit(); | ||
}); | ||
}; | ||
const revalidate = (invalidateKey) => { | ||
if (!invalidateKey) | ||
return; | ||
if (invalidateKey && invalidateKey instanceof import_hyper_fetch4.Command) { | ||
cache.events.revalidate((0, import_hyper_fetch4.getCommandKey)(invalidateKey)); | ||
} else { | ||
cache.events.revalidate(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_react_lifecycle_hooks5.useDidMount)(() => { | ||
addDataListener(command); | ||
}); | ||
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 retries() { | ||
setRenderKey("retries"); | ||
return state.retries; | ||
}, | ||
get timestamp() { | ||
setRenderKey("timestamp"); | ||
return state.timestamp; | ||
}, | ||
abort: callbacks.abort | ||
}, actions), handlers), { | ||
isDebouncing: false, | ||
isRefreshed: false, | ||
revalidate | ||
}); | ||
}; | ||
// src/use-submit/use-submit.constants.ts | ||
var useSubmitDefaultOptions = { | ||
disabled: false, | ||
dependencyTracking: true, | ||
cacheOnMount: true, | ||
initialData: null, | ||
debounce: false, | ||
debounceTime: 400, | ||
suspense: false, | ||
shouldThrow: false, | ||
invalidate: [], | ||
deepCompare: true | ||
}; | ||
// src/use-queue/use-queue.hooks.ts | ||
var import_react6 = require("react"); | ||
var import_hyper_fetch5 = require("@better-typed/hyper-fetch"); | ||
var import_react_lifecycle_hooks6 = require("@better-typed/react-lifecycle-hooks"); | ||
var useQueue = (command, options = useQueueDefaultOptions) => { | ||
const { queueType = useQueueDefaultOptions.queueType } = options; | ||
const { abortKey, queueKey, builder } = command; | ||
const { commandManager } = builder; | ||
const dispatcher = (0, import_hyper_fetch5.getCommandDispatcher)(command, queueType); | ||
const unmountCallbacks = (0, import_react6.useRef)(null); | ||
const [stopped, setStopped] = (0, import_react6.useState)(false); | ||
const [requests, setRequests] = (0, import_react6.useState)([]); | ||
const createRequestsArray = (queueElements) => { | ||
return queueElements.map((req) => __spreadProps(__spreadValues({}, req), { | ||
stopRequest: () => dispatcher[0].stopRequest(queueKey, req.requestId), | ||
startRequest: () => dispatcher[0].startRequest(queueKey, req.requestId), | ||
deleteRequest: () => dispatcher[0].delete(queueKey, req.requestId, abortKey) | ||
})); | ||
}; | ||
const getInitialState2 = () => { | ||
const [queue] = dispatcher; | ||
const commandQueue = queue.getQueue(queueKey); | ||
setStopped(commandQueue.stopped); | ||
setRequests(createRequestsArray(commandQueue.requests)); | ||
}; | ||
const mountEvents = () => { | ||
var _a; | ||
const [queue] = dispatcher; | ||
const unmountChange = queue.events.onQueueChange(queueKey, (values) => { | ||
setStopped(values.stopped); | ||
setRequests(createRequestsArray(values.requests)); | ||
}); | ||
const unmountDownload = commandManager.events.onDownloadProgress(queueKey, (progress, { requestId }) => { | ||
setRequests((prev) => prev.map((el) => el.requestId === requestId ? __spreadProps(__spreadValues({}, el), { downloading: progress }) : el)); | ||
}); | ||
const unmountUpload = commandManager.events.onDownloadProgress(queueKey, (progress, { requestId }) => { | ||
setRequests((prev) => prev.map((el) => el.requestId === requestId ? __spreadProps(__spreadValues({}, el), { uploading: progress }) : el)); | ||
}); | ||
const unmountStatus = queue.events.onQueueStatus(queueKey, (values) => { | ||
setStopped(values.stopped); | ||
setRequests(createRequestsArray(values.requests)); | ||
}); | ||
const unmount = () => { | ||
unmountStatus(); | ||
unmountChange(); | ||
unmountDownload(); | ||
unmountUpload(); | ||
}; | ||
(_a = unmountCallbacks.current) == null ? void 0 : _a.call(unmountCallbacks); | ||
unmountCallbacks.current = unmount; | ||
return unmount; | ||
}; | ||
(0, import_react_lifecycle_hooks6.useDidMount)(getInitialState2); | ||
(0, import_react_lifecycle_hooks6.useDidUpdate)(mountEvents, [stopped, requests, setRequests, setStopped], true); | ||
return { | ||
stopped, | ||
requests, | ||
stop: () => dispatcher[0].stop(queueKey), | ||
pause: () => dispatcher[0].pause(queueKey), | ||
start: () => dispatcher[0].start(queueKey) | ||
}; | ||
}; | ||
// src/use-queue/use-queue.constants.ts | ||
var useQueueDefaultOptions = { | ||
queueType: "auto" | ||
}; | ||
// src/use-cache/use-cache.hooks.ts | ||
var import_react7 = require("react"); | ||
var import_hyper_fetch6 = require("@better-typed/hyper-fetch"); | ||
var useCache = (command, { | ||
dependencyTracking = useCacheDefaultOptions.dependencyTracking, | ||
initialData = useCacheDefaultOptions.initialData, | ||
deepCompare = useCacheDefaultOptions.deepCompare | ||
} = useCacheDefaultOptions) => { | ||
const { cacheKey, builder } = command; | ||
const { cache, loggerManager } = builder; | ||
const logger = (0, import_react7.useRef)(loggerManager.init("useCache")).current; | ||
const [dispatcher] = (0, import_hyper_fetch6.getCommandDispatcher)(command); | ||
const [state, actions, { setRenderKey, setCacheData }] = useDependentState({ | ||
logger, | ||
command, | ||
dispatcher, | ||
initialData, | ||
deepCompare, | ||
dependencyTracking | ||
}); | ||
const [callbacks] = useCommandEvents({ | ||
state, | ||
logger, | ||
actions, | ||
command, | ||
dispatcher, | ||
setCacheData | ||
}); | ||
const revalidate = (revalidateKey) => { | ||
if (revalidateKey && revalidateKey instanceof import_hyper_fetch6.Command) { | ||
cache.events.revalidate(`/${(0, import_hyper_fetch6.getCommandKey)(revalidateKey, true)}/`); | ||
} else if (revalidateKey) { | ||
cache.events.revalidate(revalidateKey); | ||
} else { | ||
cache.events.revalidate(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 retries() { | ||
setRenderKey("retries"); | ||
return state.retries; | ||
}, | ||
get timestamp() { | ||
setRenderKey("timestamp"); | ||
return state.timestamp; | ||
}, | ||
onCacheError: callbacks.onError, | ||
onCacheSuccess: callbacks.onSuccess, | ||
onCacheChange: callbacks.onFinished | ||
}, actions), { | ||
revalidate | ||
}); | ||
}; | ||
// src/use-cache/use-cache.constants.ts | ||
var useCacheDefaultOptions = { | ||
dependencyTracking: true, | ||
initialData: null, | ||
deepCompare: true | ||
}; | ||
// src/use-app-manager/use-app-manager.hooks.ts | ||
var import_react8 = require("react"); | ||
var import_react_lifecycle_hooks7 = require("@better-typed/react-lifecycle-hooks"); | ||
var useAppManager = (builder) => { | ||
const [online, setIsOnline] = (0, import_react8.useState)(builder.appManager.isOnline); | ||
const [focused, setIsFocused] = (0, import_react8.useState)(builder.appManager.isFocused); | ||
const mountEvents = () => { | ||
const unmountIsOnline = builder.appManager.events.onOnline(() => setIsOnline(true)); | ||
const unmountIsOffline = builder.appManager.events.onOffline(() => setIsOnline(false)); | ||
const unmountIsFocus = builder.appManager.events.onFocus(() => setIsFocused(true)); | ||
const unmountIsBlur = builder.appManager.events.onBlur(() => setIsFocused(false)); | ||
return () => { | ||
unmountIsOnline(); | ||
unmountIsOffline(); | ||
unmountIsFocus(); | ||
unmountIsBlur(); | ||
}; | ||
}; | ||
const setOnline = (isOnline) => { | ||
builder.appManager.setOnline(isOnline); | ||
}; | ||
const setFocused = (isFocused) => { | ||
builder.appManager.setFocused(isFocused); | ||
}; | ||
(0, import_react_lifecycle_hooks7.useDidMount)(mountEvents); | ||
return { isOnline: online, isFocused: focused, setOnline, setFocused }; | ||
}; | ||
var ie=Object.defineProperty,Be=Object.defineProperties,je=Object.getOwnPropertyDescriptor,Ne=Object.getOwnPropertyDescriptors,We=Object.getOwnPropertyNames,De=Object.getOwnPropertySymbols;var Ue=Object.prototype.hasOwnProperty,$e=Object.prototype.propertyIsEnumerable;var Oe=(e,t,r)=>t in e?ie(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,k=(e,t)=>{for(var r in t||(t={}))Ue.call(t,r)&&Oe(e,r,t[r]);if(De)for(var r of De(t))$e.call(t,r)&&Oe(e,r,t[r]);return e},P=(e,t)=>Be(e,Ne(t));var Ge=(e,t)=>{for(var r in t)ie(e,r,{get:t[r],enumerable:!0})},Je=(e,t,r,g)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of We(t))!Ue.call(e,i)&&i!==r&&ie(e,i,{get:()=>t[i],enumerable:!(g=je(t,i))||g.enumerable});return e};var ze=e=>Je(ie({},"__esModule",{value:!0}),e);var re=(e,t,r)=>new Promise((g,i)=>{var C=a=>{try{u(r.next(a))}catch(y){i(y)}},d=a=>{try{u(r.throw(a))}catch(y){i(y)}},u=a=>a.done?g(a.value):Promise.resolve(a.value).then(C,d);u((r=r.apply(e,t)).next())});var et={};Ge(et,{UseTrackedState:()=>G,getDetailsState:()=>N,getInitialState:()=>de,getTimestamp:()=>Fe,getValidCacheData:()=>qe,initialState:()=>j,isEmpty:()=>he,isEqual:()=>se,isStaleCacheData:()=>me,responseToCacheValue:()=>He,useAppManager:()=>Ve,useCache:()=>_e,useCacheDefaultOptions:()=>ee,useCommandEvents:()=>$,useDebounce:()=>_,useFetch:()=>Xe,useFetchDefaultOptions:()=>v,useQueue:()=>Ze,useQueueDefaultOptions:()=>Te,useSubmit:()=>Ye,useSubmitDefaultOptions:()=>W});module.exports=ze(et);var Ie=require("react"),V=require("@better-typed/react-lifecycle-hooks"),ae=require("@better-typed/hyper-fetch");var L=require("react"),ke=require("@better-typed/hyper-fetch"),pe=require("@better-typed/react-lifecycle-hooks"),$=({command:e,dispatcher:t,logger:r,actions:g,setCacheData:i})=>{let{cache:C,commandManager:d}=e.builder,u=(0,pe.useIsMounted)(),a=(0,L.useRef)(null),y=(0,L.useRef)(null),T=(0,L.useRef)(null),h=(0,L.useRef)(null),R=(0,L.useRef)(null),s=(0,L.useRef)(null),O=(0,L.useRef)(null),x=(0,L.useRef)(null),b=(0,L.useRef)(null),f=(0,L.useRef)(new Map),q=(0,L.useRef)(null),M=n=>{let c=f.current.get(n);c==null||c.unmount(),f.current.delete(n)},A=()=>{let n=f.current;Array.from(n.values()).forEach(l=>{l.unmount()}),n.clear()},o=(n,c,l)=>{var H,X,Y,D,Q;if(!u)return r.debug("Callback cancelled, component is unmounted");let{isOffline:F,isFailed:I,isCanceled:te}=l;e.offline&&F&&I?(r.debug("Performing offline error callback",{data:c,details:l}),(H=h.current)==null||H.call(h,{response:c[1],command:n,details:l})):te?(r.debug("Performing abort callback",{data:c,details:l}),(X=T.current)==null||X.call(T,{response:c[1],command:n,details:l})):I?(r.debug("Performing error callback",{data:c,details:l}),(D=y.current)==null||D.call(y,{response:c[1],command:n,details:l})):(r.debug("Performing success callback",{data:c,details:l}),(Y=a.current)==null||Y.call(a,{response:c[0],command:n,details:l})),(Q=R.current)==null||Q.call(R,{response:c,command:n,details:l})},p=n=>({isLoading:c})=>{let l=!c&&!t.hasRunningRequests(n);(c||l)&&g.setLoading(c,!1)},m=(n,c)=>{var l;(l=x==null?void 0:x.current)==null||l.call(x,n,c)},U=(n,c)=>{var l;(l=b==null?void 0:b.current)==null||l.call(b,n,c)},E=n=>c=>{var l;(l=s==null?void 0:s.current)==null||l.call(s,{command:n,details:c})},S=n=>c=>{var l;(l=O==null?void 0:O.current)==null||l.call(O,{command:n,details:c})},K=n=>(c,l)=>{o(n,c,l)},w=({requestId:n})=>{M(n)},ce=n=>()=>{let c=[null,(0,ke.getErrorMessage)("abort"),0],l={retries:0,timestamp:+new Date,isFailed:!1,isCanceled:!0,isOffline:!1};o(n,c,l)},B=()=>{var n;(n=q.current)==null||n.unmount(),q.current=null},ye=n=>{let c=d.events.onLoading(n.queueKey,p(n.queueKey)),l=C.events.onData(n.cacheKey,i),F=d.events.onAbort(n.abortKey,ce(n)),I=()=>{c(),l(),F()};return B(),q.current={unmount:I},I},ge=(n,c)=>{if(!c){let{queueKey:D,cacheKey:Q}=n,ne=d.events.onRequestStart(D,E(n)),Z=d.events.onResponseStart(D,S(n)),Ce=d.events.onUploadProgress(D,U),Ee=d.events.onDownloadProgress(D,m),Qe=d.events.onResponse(Q,K(n)),Se=()=>{Ee(),Ce(),ne(),Z(),Qe()};return f.current.set(D,{unmount:Se}),Se}let l=d.events.onRemoveById(c,w),F=d.events.onRequestStartById(c,E(n)),I=d.events.onResponseStartById(c,S(n)),te=d.events.onResponseById(c,K(n)),H=d.events.onUploadProgressById(c,U),X=d.events.onDownloadProgressById(c,m),Y=()=>{l(),X(),H(),F(),I(),te()};return f.current.set(c,{unmount:Y}),Y},be=()=>{let{abortKey:n}=e;t.getAllRunningRequest().forEach(l=>{l.command.abortKey===n&&t.delete(l.command.queueKey,l.requestId,n)})};return(0,pe.useWillUnmount)(()=>{A(),B()}),[{abort:be,onSuccess:n=>{a.current=n},onError:n=>{y.current=n},onAbort:n=>{T.current=n},onOfflineError:n=>{h.current=n},onFinished:n=>{R.current=n},onRequestStart:n=>{s.current=n},onResponseStart:n=>{O.current=n},onDownloadProgress:n=>{x.current=n},onUploadProgress:n=>{b.current=n}},{addDataListener:ye,clearDataListener:B,addLifecycleListeners:ge,removeLifecycleListener:M,clearLifecycleListeners:A}]};var ve=require("react"),le=require("@better-typed/react-lifecycle-hooks"),_=(e=600)=>{let t=(0,ve.useRef)({time:e,timer:null});(0,le.useDidUpdate)(()=>{t.current.time=e},[e]);let r=()=>{t.current.timer!==null&&clearTimeout(t.current.timer),t.current.timer=null},g=(i,C)=>{r(),t.current.timer=setTimeout(()=>{i()},C||t.current.time)};return(0,le.useWillUnmount)(r),{debounce:g,resetDebounce:r,active:!!t.current.timer}};var j={data:null,error:null,loading:!1,status:null,retries:0,timestamp:null};var Re=require("react"),oe=require("@better-typed/react-lifecycle-hooks");var he=e=>{let t=Object.prototype.toString.call(e);return Array.isArray(e)?!e.length:typeof e=="object"&&e!==null&&t==="[object Object]"?!Object.keys(e).length:!1},se=(e,t)=>{let r=Object.prototype.toString.call(e),g=Object.prototype.toString.call(t),i=typeof e,C=typeof t,d=a=>i===a&&C===a,u=a=>r===a&&g===a;return r!==g?!1:e===null&&t===null||d("number")&&Number.isNaN(e)&&Number.isNaN(t)||he(e)&&he(t)?!0:Array.isArray(e)&&Array.isArray(t)?e.length!==t.length?!1:!e.some((a,y)=>!se(a,t[y])):d("object")&&u("[object Object]")?Object.keys(e).length!==Object.keys(t).length?!1:!Object.entries(e).some(([a,y])=>!se(y,t[a])):e instanceof Date&&t instanceof Date?+e==+t:e===t};var N=(e,t)=>k({retries:(e==null?void 0:e.retries)||0,timestamp:+new Date,isFailed:!1,isCanceled:!1,isOffline:!1},t),me=(e,t)=>t?e?+new Date>+t+e:!1:!0,qe=(e,t,r)=>!me(e.cacheTime,r==null?void 0:r.details.timestamp)&&r?r:t?{data:t,details:N(),cacheTime:1e3,clearKey:e.builder.cache.clearKey}:null,Fe=e=>e?new Date(e):null,He=e=>e?{data:e,details:N(),cacheTime:1e3,clearKey:""}:null,de=(e,t,r)=>{var y,T,h;let{builder:g,cacheKey:i}=r,{cache:C}=g,d=C.get(i),u=qe(r,e,d),a=t.hasRunningRequests(r.queueKey);return P(k({},j),{data:((y=u==null?void 0:u.data)==null?void 0:y[0])||j.data,error:((T=u==null?void 0:u.data)==null?void 0:T[1])||j.error,status:((h=u==null?void 0:u.data)==null?void 0:h[2])||j.status,retries:(u==null?void 0:u.details.retries)||j.retries,timestamp:Fe((u==null?void 0:u.details.timestamp)||j.timestamp),loading:a!=null?a:j.loading})};var G=({command:e,dispatcher:t,initialData:r,deepCompare:g,dependencyTracking:i,defaultCacheEmitting:C=!0})=>{let{builder:d,cacheKey:u,queueKey:a,cacheTime:y}=e,{cache:T,commandManager:h}=d,R=(0,oe.useForceUpdate)(),s=(0,Re.useRef)(de(r,t,e)),O=(0,Re.useRef)([]),x=()=>{var p;let o=T.get(u);return me(y,(o==null?void 0:o.details.timestamp)||((p=s.current)==null?void 0:p.timestamp))},b=o=>{O.current.some(m=>o.includes(m))&&R()},f=o=>{O.current.includes(o)||O.current.push(o)};(0,oe.useDidUpdate)(()=>{s.current.loading=t.hasRunningRequests(a);let o=de(r,t,e),p=(r==null?void 0:r[0])===s.current.data,m=!!(s.current.data||s.current.error)&&!p,U=!m&&s.current.data,E=m&&!s.current.data;(U||E)&&(s.current=o)},[u,a],!0),(0,oe.useDidUpdate)(()=>{(()=>{i||Object.keys(s.current).forEach(p=>f(p))})()},[i],!0);let q=(o,p)=>typeof g=="function"?g(o,p):g?se(o,p):!1,M=o=>re(void 0,null,function*(){let p={data:o.data[0],error:o.data[1],status:o.data[2],retries:o.details.retries,timestamp:new Date(o.details.timestamp),loading:s.current.loading},m=Object.keys(p).filter(U=>{let E=U,S=s.current[E],K=p[E];return!q(S,K)});s.current=k(k({},s.current),p),b(m)}),A={setData:(o,p=C)=>{if(p){let m=s.current;T.set(e,[o,m.error,m.status],N(s.current))}else s.current.data=o,b(["data"])},setError:(o,p=C)=>{if(p){let m=s.current;T.set(e,[m.data,o,m.status],N(s.current,{isFailed:!!o}))}else s.current.error=o,b(["error"])},setLoading:(o,p=!0)=>{p?h.events.emitLoading(a,"",{queueKey:a,requestId:"",isLoading:o,isRetry:!1,isOffline:!1}):(s.current.loading=o,b(["loading"]))},setStatus:(o,p=C)=>{if(p){let m=s.current;T.set(e,[m.data,m.error,o],N(s.current))}else s.current.status=o,b(["status"])},setRetries:(o,p=C)=>{if(p){let m=s.current;T.set(e,[m.data,m.error,m.status],N(s.current,{retries:o}))}else s.current.retries=o,b(["retries"])},setTimestamp:(o,p=C)=>{if(p){let m=s.current;T.set(e,[m.data,m.error,m.status],N(s.current,{timestamp:+o}))}else s.current.timestamp=o,b(["timestamp"])}};return[s.current,A,{setRenderKey:f,setCacheData:M,getStaleStatus:x}]};var Xe=(e,{dependencies:t=v.dependencies,disabled:r=v.disabled,dependencyTracking:g=v.dependencyTracking,revalidateOnMount:i=v.revalidateOnMount,initialData:C=v.initialData,refresh:d=v.refresh,refreshTime:u=v.refreshTime,refreshBlurred:a=v.refreshBlurred,refreshOnTabBlur:y=v.refreshOnTabBlur,refreshOnTabFocus:T=v.refreshOnTabFocus,refreshOnReconnect:h=v.refreshOnReconnect,debounce:R=v.debounce,debounceTime:s=v.debounceTime,deepCompare:O=v.deepCompare}=v)=>{let x=JSON.stringify(e.dump()),b=_(s),f=_(u),{cacheKey:q,queueKey:M,builder:A}=e,{cache:o,fetchDispatcher:p,appManager:m,loggerManager:U}=A,E=(0,Ie.useRef)(U.init("useFetch")).current,[S,K,{setRenderKey:w,setCacheData:ce,getStaleStatus:B}]=G({logger:E,command:e,dispatcher:p,initialData:C,deepCompare:O,dependencyTracking:g}),[ye,ge]=$({logger:E,actions:K,command:e,dispatcher:p,setCacheData:ce}),{addDataListener:be,addLifecycleListeners:n,clearDataListener:c,clearLifecycleListeners:l}=ge,F=()=>{r?E.debug("Cannot add to fetch queue",{disabled:r}):(E.debug("Fetching data"),p.add(e))};function I(){!d||(E.debug(`Starting refresh counter, request will be send in ${u}ms`),f.debounce(()=>{let D=!m.isFocused,Q=p.hasRunningRequests(e.queueKey),ne=p.getIsActiveQueue(e.queueKey),Z=Q||ne;(D&&a&&!Z||!D&&!Z)&&(F(),E.debug("Performing refresh request")),I()}))}let te=D=>{D&&D instanceof ae.Command?o.revalidate((0,ae.getCommandKey)(D)):D&&!(D instanceof ae.Command)?o.revalidate(D):(F(),I())},H=()=>{let D=B(),Q=p.getIsActiveQueue(M);(i||D&&!Q)&&F()},X=()=>{R?(E.debug("Debouncing request",{queueKey:M,command:e}),b.debounce(()=>F())):F()};return(0,V.useDidUpdate)(()=>{be(e),n(e);let D=m.events.onFocus(()=>{T&&(F(),I())}),Q=m.events.onBlur(()=>{y&&(F(),I())}),ne=m.events.onOnline(()=>{h&&(F(),I())}),Z=o.events.onRevalidate(q,F);return()=>{c(),l(),D(),Q(),ne(),Z()}},[x],!0),(0,V.useDidMount)(H),(0,V.useDidUpdate)(X,[x,...t]),(0,V.useDidUpdate)(I,[x,...t,r,d,u],!0),P(k(k({get data(){return w("data"),S.data},get error(){return w("error"),S.error},get loading(){return w("loading"),S.loading},get status(){return w("status"),S.status},get retries(){return w("retries"),S.retries},get timestamp(){return w("timestamp"),S.timestamp}},K),ye),{isDebouncing:b.active,revalidate:te})};var we=require("@better-typed/hyper-fetch"),v={dependencies:[],disabled:!1,dependencyTracking:!0,revalidateOnMount:!0,initialData:null,refresh:!1,refreshTime:we.DateInterval.hour,refreshBlurred:!0,refreshOnTabBlur:!1,refreshOnTabFocus:!1,refreshOnReconnect:!1,debounce:!1,debounceTime:400,deepCompare:!0};var Me=require("react"),J=require("@better-typed/hyper-fetch"),Pe=require("@better-typed/react-lifecycle-hooks");var Ye=(e,{disabled:t=W.disabled,dependencyTracking:r=W.dependencyTracking,initialData:g=W.initialData,debounce:i=W.debounce,debounceTime:C=W.debounceTime,deepCompare:d=W.deepCompare}=W)=>{let{builder:u}=e,{cache:a,submitDispatcher:y,loggerManager:T}=u,h=(0,Me.useRef)(T.init("useSubmit")).current,R=_(C),[s,O,{setRenderKey:x,setCacheData:b}]=G({logger:h,command:e,dispatcher:y,initialData:g,deepCompare:d,dependencyTracking:r}),[f,q]=$({logger:h,actions:O,command:e,dispatcher:y,setCacheData:b}),{addDataListener:M,addLifecycleListeners:A}=q,o=(...U)=>{let E=U[0],S=e.clone(E);if(t)return h.warning("Cannot submit request",{disabled:t,options:E}),[null,null,0];let K=()=>(M(S),(0,J.commandSendRequest)(S,"submit",w=>{A(S,w)}));return new Promise(w=>{(()=>re(void 0,null,function*(){if(h.debug("Submitting request",{disabled:t,options:E}),i)R.debounce(()=>re(void 0,null,function*(){let B=yield K();w(B)}));else{let B=yield K();w(B)}}))()})},p=U=>{!U||(U&&U instanceof J.Command?a.revalidate((0,J.getCommandKey)(U)):U instanceof J.Command||a.revalidate(U))},m={onSubmitSuccess:f.onSuccess,onSubmitError:f.onError,onSubmitFinished:f.onFinished,onSubmitRequestStart:f.onRequestStart,onSubmitResponseStart:f.onResponseStart,onSubmitDownloadProgress:f.onDownloadProgress,onSubmitUploadProgress:f.onUploadProgress,onSubmitOfflineError:f.onOfflineError,onSubmitAbort:f.onAbort};return(0,Pe.useDidMount)(()=>{M(e)}),P(k(k({submit:o,get data(){return x("data"),s.data},get error(){return x("error"),s.error},get submitting(){return x("loading"),s.loading},get status(){return x("status"),s.status},get retries(){return x("retries"),s.retries},get timestamp(){return x("timestamp"),s.timestamp},abort:f.abort},O),m),{isDebouncing:R.active,revalidate:p})};var W={disabled:!1,dependencyTracking:!0,cacheOnMount:!0,initialData:null,debounce:!1,debounceTime:400,suspense:!1,shouldThrow:!1,invalidate:[],deepCompare:!0};var ue=require("react"),Le=require("@better-typed/hyper-fetch"),fe=require("@better-typed/react-lifecycle-hooks");var Ze=(e,t=Te)=>{let{queueType:r=Te.queueType}=t,{abortKey:g,queueKey:i,builder:C}=e,{commandManager:d}=C,[u]=(0,Le.getCommandDispatcher)(e,r),a=(0,ue.useRef)(null),[y,T]=(0,ue.useState)(!1),[h,R]=(0,ue.useState)([]),s=f=>f.map(q=>P(k({},q),{stopRequest:()=>u[0].stopRequest(i,q.requestId),startRequest:()=>u[0].startRequest(i,q.requestId),deleteRequest:()=>u[0].delete(i,q.requestId,g)})),O=()=>{let f=u.getQueue(i);T(f.stopped),R(s(f.requests))},x=f=>{T(f.stopped),R(s(f.requests))},b=()=>{var p;let f=u.events.onQueueChange(i,x),q=u.events.onQueueStatus(i,x),M=d.events.onDownloadProgress(i,(m,{requestId:U})=>{R(E=>E.map(S=>S.requestId===U?P(k({},S),{downloading:m}):S))}),A=d.events.onUploadProgress(i,(m,{requestId:U})=>{R(E=>E.map(S=>S.requestId===U?P(k({},S),{uploading:m}):S))}),o=()=>{q(),f(),M(),A()};return(p=a.current)==null||p.call(a),a.current=o,o};return(0,fe.useDidMount)(O),(0,fe.useDidUpdate)(b,[y,h,R,T],!0),{stopped:y,requests:h,stop:()=>u[0].stop(i),pause:()=>u[0].pause(i),start:()=>u[0].start(i)}};var Te={queueType:"auto"};var Ae=require("react"),z=require("@better-typed/hyper-fetch");var _e=(e,{dependencyTracking:t=ee.dependencyTracking,initialData:r=ee.initialData,deepCompare:g=ee.deepCompare}=ee)=>{let{cacheKey:i,builder:C}=e,{cache:d,loggerManager:u}=C,a=(0,Ae.useRef)(u.init("useCache")).current,[y]=(0,z.getCommandDispatcher)(e),[T,h,{setRenderKey:R,setCacheData:s}]=G({logger:a,command:e,dispatcher:y,initialData:r,deepCompare:g,dependencyTracking:t}),[O]=$({logger:a,actions:h,command:e,dispatcher:y,setCacheData:s}),x=b=>{b&&b instanceof z.Command?d.revalidate(`/${(0,z.getCommandKey)(b,!0)}/`):b&&!(b instanceof z.Command)?d.revalidate(b):d.revalidate(i)};return P(k({get data(){return R("data"),T.data},get error(){return R("error"),T.error},get loading(){return R("loading"),T.loading},get status(){return R("status"),T.status},get retries(){return R("retries"),T.retries},get timestamp(){return R("timestamp"),T.timestamp},onCacheError:O.onError,onCacheSuccess:O.onSuccess,onCacheChange:O.onFinished},h),{revalidate:x})};var ee={dependencyTracking:!0,initialData:null,deepCompare:!0};var xe=require("react"),Ke=require("@better-typed/react-lifecycle-hooks"),Ve=e=>{let[t,r]=(0,xe.useState)(e.appManager.isOnline),[g,i]=(0,xe.useState)(e.appManager.isFocused),C=()=>{let a=e.appManager.events.onOnline(()=>r(!0)),y=e.appManager.events.onOffline(()=>r(!1)),T=e.appManager.events.onFocus(()=>i(!0)),h=e.appManager.events.onBlur(()=>i(!1));return()=>{a(),y(),T(),h()}},d=a=>{e.appManager.setOnline(a)},u=a=>{e.appManager.setFocused(a)};return(0,Ke.useDidMount)(C),{isOnline:t,isFocused:g,setOnline:d,setFocused:u}}; | ||
//# sourceMappingURL=index.cjs.js.map |
@@ -1,1066 +0,2 @@ | ||
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
var __async = (__this, __arguments, generator) => { | ||
return new Promise((resolve, reject) => { | ||
var fulfilled = (value) => { | ||
try { | ||
step(generator.next(value)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}; | ||
var rejected = (value) => { | ||
try { | ||
step(generator.throw(value)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}; | ||
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); | ||
step((generator = generator.apply(__this, __arguments)).next()); | ||
}); | ||
}; | ||
// src/use-fetch/use-fetch.hooks.ts | ||
import { useRef as useRef4 } from "react"; | ||
import { useDidUpdate as useDidUpdate4, useDidMount } from "@better-typed/react-lifecycle-hooks"; | ||
import { Command, getCommandKey } from "@better-typed/hyper-fetch"; | ||
// src/helpers/use-command-events/use-command-events.hooks.ts | ||
import { useRef } from "react"; | ||
import { | ||
isFailedRequest, | ||
getErrorMessage | ||
} from "@better-typed/hyper-fetch"; | ||
import { useDidUpdate, useIsMounted, useWillUnmount } from "@better-typed/react-lifecycle-hooks"; | ||
var useCommandEvents = ({ | ||
command, | ||
dispatcher, | ||
logger, | ||
state, | ||
actions, | ||
setCacheData, | ||
initializeCallbacks = false | ||
}) => { | ||
const { cache, appManager, commandManager } = command.builder; | ||
const commandDump = command.dump(); | ||
const isMounted = useIsMounted(); | ||
const onSuccessCallback = useRef(null); | ||
const onErrorCallback = useRef(null); | ||
const onAbortCallback = useRef(null); | ||
const onOfflineErrorCallback = useRef(null); | ||
const onFinishedCallback = useRef(null); | ||
const onRequestStartCallback = useRef(null); | ||
const onResponseStartCallback = useRef(null); | ||
const onDownloadProgressCallback = useRef(null); | ||
const onUploadProgressCallback = useRef(null); | ||
const lifecycleEvents = useRef(/* @__PURE__ */ new Map()); | ||
const dataEvents = useRef(null); | ||
const removeLifecycleListener = (requestId) => { | ||
const event = lifecycleEvents.current.get(requestId); | ||
event == null ? void 0 : event.unmount(); | ||
lifecycleEvents.current.delete(requestId); | ||
}; | ||
const clearLifecycleListeners = () => { | ||
const events = lifecycleEvents.current; | ||
const listeners = Array.from(events.values()); | ||
listeners.forEach((value) => { | ||
value.unmount(); | ||
}); | ||
events.clear(); | ||
}; | ||
const handleResponseCallbacks = (cmd, data, details) => { | ||
var _a, _b, _c, _d, _e; | ||
if (!isMounted) | ||
return logger.debug("Callback cancelled, component is unmounted"); | ||
const { isOffline, isFailed, isCanceled } = details; | ||
if (command.offline && isOffline && isFailed) { | ||
logger.debug("Performing offline error callback", { data, details }); | ||
(_a = onOfflineErrorCallback.current) == null ? void 0 : _a.call(onOfflineErrorCallback, { response: data[1], command: cmd, details }); | ||
} else if (isCanceled) { | ||
logger.debug("Performing abort callback", { data, details }); | ||
(_b = onAbortCallback.current) == null ? void 0 : _b.call(onAbortCallback, { response: data[1], command: cmd, details }); | ||
} else if (!isFailed) { | ||
logger.debug("Performing success callback", { data, details }); | ||
(_c = onSuccessCallback.current) == null ? void 0 : _c.call(onSuccessCallback, { response: data[0], command: cmd, details }); | ||
} else { | ||
logger.debug("Performing error callback", { data, details }); | ||
(_d = onErrorCallback.current) == null ? void 0 : _d.call(onErrorCallback, { response: data[1], command: cmd, details }); | ||
} | ||
(_e = onFinishedCallback.current) == null ? void 0 : _e.call(onFinishedCallback, { response: data, command: cmd, details }); | ||
}; | ||
const handleInitialCallbacks = () => { | ||
const hasData = state.data && state.error && state.timestamp; | ||
if (hasData && initializeCallbacks) { | ||
const details = { | ||
retries: state.retries, | ||
timestamp: new Date(state.timestamp), | ||
isFailed: isFailedRequest([state.data, state.error, state.status]), | ||
isCanceled: false, | ||
isOffline: !appManager.isOnline | ||
}; | ||
handleResponseCallbacks(command, [state.data, state.error, state.status], details); | ||
} | ||
}; | ||
const handleGetLoadingEvent = (queueKey) => { | ||
return ({ isLoading }) => { | ||
const canDisableLoading = !isLoading && !dispatcher.hasRunningRequests(queueKey); | ||
if (isLoading || canDisableLoading) { | ||
actions.setLoading(isLoading, false); | ||
} | ||
}; | ||
}; | ||
const handleDownloadProgress = (progress) => { | ||
var _a; | ||
(_a = onDownloadProgressCallback == null ? void 0 : onDownloadProgressCallback.current) == null ? void 0 : _a.call(onDownloadProgressCallback, progress); | ||
}; | ||
const handleUploadProgress = (progress) => { | ||
var _a; | ||
(_a = onUploadProgressCallback == null ? void 0 : onUploadProgressCallback.current) == null ? void 0 : _a.call(onUploadProgressCallback, progress); | ||
}; | ||
const handleRequestStart = (cmd) => { | ||
return (details) => { | ||
var _a; | ||
(_a = onRequestStartCallback == null ? void 0 : onRequestStartCallback.current) == null ? void 0 : _a.call(onRequestStartCallback, { command: cmd, details }); | ||
}; | ||
}; | ||
const handleResponseStart = (cmd) => { | ||
return (details) => { | ||
var _a; | ||
(_a = onResponseStartCallback == null ? void 0 : onResponseStartCallback.current) == null ? void 0 : _a.call(onResponseStartCallback, { command: cmd, details }); | ||
}; | ||
}; | ||
const handleResponse = (cmd) => { | ||
return (data, details) => { | ||
handleResponseCallbacks(cmd, data, details); | ||
}; | ||
}; | ||
const handleRemove = (requestId) => { | ||
removeLifecycleListener(requestId); | ||
}; | ||
const handleAbort = (cmd) => { | ||
return () => { | ||
const data = [ | ||
null, | ||
getErrorMessage("abort"), | ||
0 | ||
]; | ||
const details = { | ||
retries: 0, | ||
timestamp: new Date(), | ||
isFailed: false, | ||
isCanceled: true, | ||
isOffline: false | ||
}; | ||
handleResponseCallbacks(cmd, data, details); | ||
}; | ||
}; | ||
const clearDataListener = () => { | ||
var _a; | ||
(_a = dataEvents.current) == null ? void 0 : _a.unmount(); | ||
dataEvents.current = null; | ||
}; | ||
const addDataListener = (cmd) => { | ||
const loadingUnmount = commandManager.events.onLoading(cmd.queueKey, handleGetLoadingEvent(cmd.queueKey)); | ||
const getResponseUnmount = cache.events.get(cmd.cacheKey, setCacheData); | ||
const abortUnmount = commandManager.events.onAbort(cmd.abortKey, handleAbort(cmd)); | ||
const unmount = () => { | ||
loadingUnmount(); | ||
getResponseUnmount(); | ||
abortUnmount(); | ||
}; | ||
clearDataListener(); | ||
dataEvents.current = { unmount }; | ||
return unmount; | ||
}; | ||
const addLifecycleListeners = (cmd, requestId) => { | ||
if (!requestId) { | ||
const { queueKey, cacheKey } = cmd; | ||
const requestStartUnmount2 = commandManager.events.onRequestStart(queueKey, handleRequestStart(cmd)); | ||
const responseStartUnmount2 = commandManager.events.onResponseStart(queueKey, handleResponseStart(cmd)); | ||
const uploadUnmount2 = commandManager.events.onUploadProgress(queueKey, handleUploadProgress); | ||
const downloadUnmount2 = commandManager.events.onDownloadProgress(queueKey, handleDownloadProgress); | ||
const responseUnmount2 = commandManager.events.onResponse(cacheKey, handleResponse(cmd)); | ||
const unmount2 = () => { | ||
downloadUnmount2(); | ||
uploadUnmount2(); | ||
requestStartUnmount2(); | ||
responseStartUnmount2(); | ||
responseUnmount2(); | ||
}; | ||
lifecycleEvents.current.set(queueKey, { unmount: unmount2 }); | ||
return unmount2; | ||
} | ||
const requestRemove = commandManager.events.onRemoveById(requestId, handleRemove); | ||
const requestStartUnmount = commandManager.events.onRequestStartById(requestId, handleRequestStart(cmd)); | ||
const responseStartUnmount = commandManager.events.onResponseStartById(requestId, handleResponseStart(cmd)); | ||
const responseUnmount = commandManager.events.onResponseById(requestId, handleResponse(cmd)); | ||
const uploadUnmount = commandManager.events.onUploadProgressById(requestId, handleUploadProgress); | ||
const downloadUnmount = commandManager.events.onDownloadProgressById(requestId, handleDownloadProgress); | ||
const unmount = () => { | ||
requestRemove(); | ||
downloadUnmount(); | ||
uploadUnmount(); | ||
requestStartUnmount(); | ||
responseStartUnmount(); | ||
responseUnmount(); | ||
}; | ||
lifecycleEvents.current.set(requestId, { unmount }); | ||
return unmount; | ||
}; | ||
const abort = () => { | ||
const { abortKey } = command; | ||
const requests = dispatcher.getAllRunningRequest(); | ||
requests.forEach((request) => { | ||
if (request.command.abortKey === abortKey) { | ||
dispatcher.delete(request.command.queueKey, request.requestId, abortKey); | ||
} | ||
}); | ||
}; | ||
useDidUpdate(handleInitialCallbacks, [commandDump.cacheKey, commandDump.queueKey], true); | ||
useWillUnmount(() => { | ||
clearLifecycleListeners(); | ||
clearDataListener(); | ||
}); | ||
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; | ||
} | ||
}, | ||
{ | ||
addDataListener, | ||
clearDataListener, | ||
addLifecycleListeners, | ||
removeLifecycleListener, | ||
clearLifecycleListeners | ||
} | ||
]; | ||
}; | ||
// src/helpers/use-debounce/use-debounce.hooks.ts | ||
import { useRef as useRef2 } from "react"; | ||
import { useWillUnmount as useWillUnmount2, useDidUpdate as useDidUpdate2 } from "@better-typed/react-lifecycle-hooks"; | ||
var useDebounce = (delay = 600) => { | ||
const debounce = useRef2({ | ||
time: delay, | ||
timer: null | ||
}); | ||
useDidUpdate2(() => { | ||
debounce.current.time = delay; | ||
}, [delay]); | ||
const resetDebounce = () => { | ||
if (debounce.current.timer !== null) | ||
clearTimeout(debounce.current.timer); | ||
debounce.current.timer = null; | ||
}; | ||
const setDebounce = (callback, time) => { | ||
resetDebounce(); | ||
debounce.current.timer = setTimeout(() => { | ||
callback(); | ||
}, time || debounce.current.time); | ||
}; | ||
useWillUnmount2(resetDebounce); | ||
return { debounce: setDebounce, resetDebounce, active: !!debounce.current.timer }; | ||
}; | ||
// src/helpers/use-dependent-state/use-dependent-state.constants.ts | ||
var initialState = { | ||
data: null, | ||
error: null, | ||
loading: false, | ||
status: null, | ||
retries: 0, | ||
timestamp: null | ||
}; | ||
// src/helpers/use-dependent-state/use-dependent-state.hooks.ts | ||
import { useRef as useRef3 } from "react"; | ||
import { useDidUpdate as useDidUpdate3, useForceUpdate } from "@better-typed/react-lifecycle-hooks"; | ||
// 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) => { | ||
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; | ||
}; | ||
// src/helpers/use-dependent-state/use-dependent-state.utils.ts | ||
var getDetailsState = (state, details) => { | ||
return __spreadValues({ | ||
retries: (state == null ? void 0 : state.retries) || 0, | ||
timestamp: new Date(), | ||
isFailed: false, | ||
isCanceled: false, | ||
isOffline: false | ||
}, details); | ||
}; | ||
var isStaleCacheData = (cacheTime, cacheTimestamp) => { | ||
if (!cacheTimestamp) | ||
return true; | ||
if (!cacheTime) | ||
return false; | ||
return +new Date() > +cacheTimestamp + cacheTime; | ||
}; | ||
var getValidCacheData = (command, initialData, cacheData) => { | ||
const isStale = isStaleCacheData(command.cacheTime, cacheData == null ? void 0 : cacheData.details.timestamp); | ||
if (!isStale && cacheData) { | ||
return cacheData; | ||
} | ||
if (initialData) { | ||
return { | ||
data: initialData, | ||
details: getDetailsState(), | ||
cacheTime: 1e3 | ||
}; | ||
} | ||
return null; | ||
}; | ||
var getTimestamp = (timestamp) => { | ||
return timestamp ? new Date(timestamp) : null; | ||
}; | ||
var responseToCacheValue = (response) => { | ||
if (!response) | ||
return null; | ||
return { | ||
data: response, | ||
details: getDetailsState(), | ||
cacheTime: 1e3 | ||
}; | ||
}; | ||
var getInitialState = (initialData, dispatcher, command) => { | ||
var _a, _b, _c; | ||
const { builder, cacheKey } = command; | ||
const { cache } = builder; | ||
const cacheData = cache.get(cacheKey); | ||
const cacheState = getValidCacheData(command, initialData, cacheData); | ||
const initialLoading = dispatcher.hasRunningRequests(command.queueKey); | ||
return __spreadProps(__spreadValues({}, initialState), { | ||
data: ((_a = cacheState == null ? void 0 : cacheState.data) == null ? void 0 : _a[0]) || initialState.data, | ||
error: ((_b = cacheState == null ? void 0 : cacheState.data) == null ? void 0 : _b[1]) || initialState.error, | ||
status: ((_c = cacheState == null ? void 0 : cacheState.data) == null ? void 0 : _c[2]) || initialState.status, | ||
retries: (cacheState == null ? void 0 : cacheState.details.retries) || initialState.retries, | ||
timestamp: getTimestamp((cacheState == null ? void 0 : cacheState.details.timestamp) || initialState.timestamp), | ||
loading: initialLoading != null ? initialLoading : initialState.loading | ||
}); | ||
}; | ||
// src/helpers/use-dependent-state/use-dependent-state.hooks.ts | ||
var useDependentState = ({ | ||
command, | ||
dispatcher, | ||
initialData, | ||
deepCompare, | ||
dependencyTracking, | ||
defaultCacheEmitting = true | ||
}) => { | ||
const { builder, cacheKey, queueKey, cacheTime } = command; | ||
const { cache, commandManager } = builder; | ||
const forceUpdate = useForceUpdate(); | ||
const state = useRef3(getInitialState(initialData, dispatcher, command)); | ||
const renderKeys = useRef3([]); | ||
const getStaleStatus = () => { | ||
const cacheData = cache.get(cacheKey); | ||
return isStaleCacheData(cacheTime, cacheData == null ? void 0 : cacheData.details.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); | ||
} | ||
}; | ||
useDidUpdate3(() => { | ||
state.current.loading = dispatcher.hasRunningRequests(queueKey); | ||
const newState = getInitialState(initialData, dispatcher, command); | ||
const hasInitialState = (initialData == null ? void 0 : initialData[0]) === 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 (shouldLoadInitialCache || shouldRemovePreviousData) { | ||
state.current = newState; | ||
} | ||
}, [cacheKey, queueKey], true); | ||
useDidUpdate3(() => { | ||
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 setCacheData = (cacheData) => __async(void 0, null, function* () { | ||
const newStateValues = { | ||
data: cacheData.data[0], | ||
error: cacheData.data[1], | ||
status: cacheData.data[2], | ||
retries: cacheData.details.retries, | ||
timestamp: new Date(cacheData.details.timestamp), | ||
loading: state.current.loading | ||
}; | ||
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 actions = { | ||
setData: (data, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [data, currentState.error, currentState.status], getDetailsState(state.current)); | ||
} else { | ||
state.current.data = data; | ||
renderKeyTrigger(["data"]); | ||
} | ||
}, | ||
setError: (error, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [currentState.data, error, currentState.status], getDetailsState(state.current, { isFailed: !!error })); | ||
} else { | ||
state.current.error = error; | ||
renderKeyTrigger(["error"]); | ||
} | ||
}, | ||
setLoading: (loading, emitToHooks = true) => { | ||
if (emitToHooks) { | ||
commandManager.events.setLoading(queueKey, "", { | ||
isLoading: loading, | ||
isRetry: false, | ||
isOffline: false | ||
}); | ||
} else { | ||
state.current.loading = loading; | ||
renderKeyTrigger(["loading"]); | ||
} | ||
}, | ||
setStatus: (status, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [currentState.data, currentState.error, status], getDetailsState(state.current)); | ||
} else { | ||
state.current.status = status; | ||
renderKeyTrigger(["status"]); | ||
} | ||
}, | ||
setRetries: (retries, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [currentState.data, currentState.error, currentState.status], getDetailsState(state.current, { retries })); | ||
} else { | ||
state.current.retries = retries; | ||
renderKeyTrigger(["retries"]); | ||
} | ||
}, | ||
setTimestamp: (timestamp, emitToCache = defaultCacheEmitting) => { | ||
if (emitToCache) { | ||
const currentState = state.current; | ||
cache.set(command, [currentState.data, currentState.error, currentState.status], getDetailsState(state.current, { timestamp })); | ||
} else { | ||
state.current.timestamp = timestamp; | ||
renderKeyTrigger(["timestamp"]); | ||
} | ||
} | ||
}; | ||
return [state.current, actions, { setRenderKey, setCacheData, getStaleStatus }]; | ||
}; | ||
// src/use-fetch/use-fetch.hooks.ts | ||
var useFetch = (command, { | ||
dependencies = useFetchDefaultOptions.dependencies, | ||
disabled = useFetchDefaultOptions.disabled, | ||
dependencyTracking = useFetchDefaultOptions.dependencyTracking, | ||
revalidateOnMount = useFetchDefaultOptions.revalidateOnMount, | ||
initialData = useFetchDefaultOptions.initialData, | ||
refresh = useFetchDefaultOptions.refresh, | ||
refreshTime = useFetchDefaultOptions.refreshTime, | ||
refreshBlurred = useFetchDefaultOptions.refreshBlurred, | ||
refreshOnTabBlur = useFetchDefaultOptions.refreshOnTabBlur, | ||
refreshOnTabFocus = useFetchDefaultOptions.refreshOnTabFocus, | ||
refreshOnReconnect = useFetchDefaultOptions.refreshOnReconnect, | ||
debounce = useFetchDefaultOptions.debounce, | ||
debounceTime = useFetchDefaultOptions.debounceTime, | ||
deepCompare = useFetchDefaultOptions.deepCompare | ||
} = useFetchDefaultOptions) => { | ||
const updateKey = JSON.stringify(command.dump()); | ||
const requestDebounce = useDebounce(debounceTime); | ||
const refreshDebounce = useDebounce(refreshTime); | ||
const { cacheKey, queueKey, builder } = command; | ||
const { cache, fetchDispatcher: dispatcher, appManager, loggerManager } = builder; | ||
const logger = useRef4(loggerManager.init("useFetch")).current; | ||
const [state, actions, { setRenderKey, setCacheData, getStaleStatus }] = useDependentState({ | ||
logger, | ||
command, | ||
dispatcher, | ||
initialData, | ||
deepCompare, | ||
dependencyTracking | ||
}); | ||
const [callbacks, listeners] = useCommandEvents({ | ||
state, | ||
logger, | ||
actions, | ||
command, | ||
dispatcher, | ||
setCacheData | ||
}); | ||
const { addDataListener, addLifecycleListeners, clearDataListener, clearLifecycleListeners } = listeners; | ||
const handleFetch = () => { | ||
if (!disabled) { | ||
logger.debug(`Adding request to fetch queue`); | ||
dispatcher.add(command); | ||
} else { | ||
logger.debug(`Cannot add to fetch queue`, { disabled }); | ||
} | ||
}; | ||
function handleRefresh() { | ||
if (!refresh) | ||
return; | ||
logger.debug(`Starting refresh counter, request will be send in ${refreshTime}ms`); | ||
refreshDebounce.debounce(() => { | ||
const isBlurred = !appManager.isFocused; | ||
const isFetching = dispatcher.hasRunningRequests(command.queueKey); | ||
const isQueued = dispatcher.getIsActiveQueue(command.queueKey); | ||
const isActive = isFetching || isQueued; | ||
const canRefreshBlurred = isBlurred && refreshBlurred && !isActive; | ||
const canRefreshFocused = !isBlurred && !isActive; | ||
if (canRefreshBlurred || canRefreshFocused) { | ||
handleFetch(); | ||
logger.debug(`Performing refresh request`); | ||
} | ||
handleRefresh(); | ||
}); | ||
} | ||
const revalidate = (invalidateKey) => { | ||
if (invalidateKey && invalidateKey instanceof Command) { | ||
cache.events.revalidate(getCommandKey(invalidateKey)); | ||
} else if (invalidateKey) { | ||
cache.events.revalidate(invalidateKey); | ||
} else { | ||
handleFetch(); | ||
handleRefresh(); | ||
} | ||
}; | ||
const initialFetchData = () => { | ||
const hasStaleData = getStaleStatus(); | ||
if (revalidateOnMount || hasStaleData) { | ||
handleFetch(); | ||
} | ||
}; | ||
const updateFetchData = () => { | ||
if (debounce) { | ||
logger.debug("Debouncing request", { queueKey, command }); | ||
requestDebounce.debounce(() => handleFetch()); | ||
} else { | ||
handleFetch(); | ||
} | ||
}; | ||
const handleMountEvents = () => { | ||
addDataListener(command); | ||
addLifecycleListeners(command); | ||
const focusUnmount = appManager.events.onFocus(() => { | ||
if (refreshOnTabFocus) { | ||
handleFetch(); | ||
handleRefresh(); | ||
} | ||
}); | ||
const blurUnmount = appManager.events.onBlur(() => { | ||
if (refreshOnTabBlur) { | ||
handleFetch(); | ||
handleRefresh(); | ||
} | ||
}); | ||
const onlineUnmount = appManager.events.onOnline(() => { | ||
if (refreshOnReconnect) { | ||
handleFetch(); | ||
handleRefresh(); | ||
} | ||
}); | ||
const revalidateUnmount = cache.events.onRevalidate(cacheKey, handleFetch); | ||
const unmount = () => { | ||
clearDataListener(); | ||
clearLifecycleListeners(); | ||
focusUnmount(); | ||
blurUnmount(); | ||
onlineUnmount(); | ||
revalidateUnmount(); | ||
}; | ||
return unmount; | ||
}; | ||
useDidUpdate4(handleMountEvents, [updateKey], true); | ||
useDidMount(initialFetchData); | ||
useDidUpdate4(updateFetchData, [updateKey, ...dependencies]); | ||
useDidUpdate4(handleRefresh, [updateKey, ...dependencies, disabled, refresh, refreshTime], 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 retries() { | ||
setRenderKey("retries"); | ||
return state.retries; | ||
}, | ||
get timestamp() { | ||
setRenderKey("timestamp"); | ||
return state.timestamp; | ||
} | ||
}, actions), callbacks), { | ||
isDebouncing: requestDebounce.active, | ||
revalidate | ||
}); | ||
}; | ||
// src/use-fetch/use-fetch.constants.ts | ||
import { DateInterval } from "@better-typed/hyper-fetch"; | ||
var useFetchDefaultOptions = { | ||
dependencies: [], | ||
disabled: false, | ||
dependencyTracking: true, | ||
revalidateOnMount: true, | ||
initialData: null, | ||
refresh: false, | ||
refreshTime: DateInterval.hour, | ||
refreshBlurred: true, | ||
refreshOnTabBlur: false, | ||
refreshOnTabFocus: false, | ||
refreshOnReconnect: false, | ||
debounce: false, | ||
debounceTime: 400, | ||
deepCompare: true | ||
}; | ||
// src/use-submit/use-submit.hooks.ts | ||
import { useRef as useRef5 } from "react"; | ||
import { | ||
Command as Command2, | ||
getCommandKey as getCommandKey2, | ||
commandSendRequest | ||
} from "@better-typed/hyper-fetch"; | ||
import { useDidMount as useDidMount2 } from "@better-typed/react-lifecycle-hooks"; | ||
var useSubmit = (command, { | ||
disabled = useSubmitDefaultOptions.disabled, | ||
dependencyTracking = useSubmitDefaultOptions.dependencyTracking, | ||
initialData = useSubmitDefaultOptions.initialData, | ||
debounce = useSubmitDefaultOptions.debounce, | ||
debounceTime = useSubmitDefaultOptions.debounceTime, | ||
deepCompare = useSubmitDefaultOptions.deepCompare | ||
} = useSubmitDefaultOptions) => { | ||
const { builder } = command; | ||
const { cache, submitDispatcher: dispatcher, loggerManager } = builder; | ||
const logger = useRef5(loggerManager.init("useSubmit")).current; | ||
const requestDebounce = useDebounce(debounceTime); | ||
const [state, actions, { setRenderKey, setCacheData }] = useDependentState({ | ||
logger, | ||
command, | ||
dispatcher, | ||
initialData, | ||
deepCompare, | ||
dependencyTracking | ||
}); | ||
const [callbacks, listeners] = useCommandEvents({ | ||
state, | ||
logger, | ||
actions, | ||
command, | ||
dispatcher, | ||
setCacheData | ||
}); | ||
const { addDataListener, addLifecycleListeners } = listeners; | ||
const handleSubmit = (...parameters) => { | ||
const options = parameters[0]; | ||
const commandClone = command.clone(options); | ||
if (disabled) { | ||
logger.debug(`Cannot add to submit queue`, { disabled, options }); | ||
return [null, null, 0]; | ||
} | ||
const triggerRequest = () => { | ||
addDataListener(commandClone); | ||
return commandSendRequest(commandClone, "submit", (requestId) => { | ||
addLifecycleListeners(commandClone, requestId); | ||
}); | ||
}; | ||
return new Promise((resolve) => { | ||
const performSubmit = () => __async(void 0, null, function* () { | ||
logger.debug(`Adding request to submit queue`, { disabled, options }); | ||
if (debounce) { | ||
requestDebounce.debounce(() => __async(void 0, null, function* () { | ||
const value = yield triggerRequest(); | ||
resolve(value); | ||
})); | ||
} else { | ||
const value = yield triggerRequest(); | ||
resolve(value); | ||
} | ||
}); | ||
performSubmit(); | ||
}); | ||
}; | ||
const revalidate = (invalidateKey) => { | ||
if (!invalidateKey) | ||
return; | ||
if (invalidateKey && invalidateKey instanceof Command2) { | ||
cache.events.revalidate(getCommandKey2(invalidateKey)); | ||
} else { | ||
cache.events.revalidate(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 | ||
}; | ||
useDidMount2(() => { | ||
addDataListener(command); | ||
}); | ||
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 retries() { | ||
setRenderKey("retries"); | ||
return state.retries; | ||
}, | ||
get timestamp() { | ||
setRenderKey("timestamp"); | ||
return state.timestamp; | ||
}, | ||
abort: callbacks.abort | ||
}, actions), handlers), { | ||
isDebouncing: false, | ||
isRefreshed: false, | ||
revalidate | ||
}); | ||
}; | ||
// src/use-submit/use-submit.constants.ts | ||
var useSubmitDefaultOptions = { | ||
disabled: false, | ||
dependencyTracking: true, | ||
cacheOnMount: true, | ||
initialData: null, | ||
debounce: false, | ||
debounceTime: 400, | ||
suspense: false, | ||
shouldThrow: false, | ||
invalidate: [], | ||
deepCompare: true | ||
}; | ||
// src/use-queue/use-queue.hooks.ts | ||
import { useState, useRef as useRef6 } from "react"; | ||
import { getCommandDispatcher } from "@better-typed/hyper-fetch"; | ||
import { useDidMount as useDidMount3, useDidUpdate as useDidUpdate5 } from "@better-typed/react-lifecycle-hooks"; | ||
var useQueue = (command, options = useQueueDefaultOptions) => { | ||
const { queueType = useQueueDefaultOptions.queueType } = options; | ||
const { abortKey, queueKey, builder } = command; | ||
const { commandManager } = builder; | ||
const dispatcher = getCommandDispatcher(command, queueType); | ||
const unmountCallbacks = useRef6(null); | ||
const [stopped, setStopped] = useState(false); | ||
const [requests, setRequests] = useState([]); | ||
const createRequestsArray = (queueElements) => { | ||
return queueElements.map((req) => __spreadProps(__spreadValues({}, req), { | ||
stopRequest: () => dispatcher[0].stopRequest(queueKey, req.requestId), | ||
startRequest: () => dispatcher[0].startRequest(queueKey, req.requestId), | ||
deleteRequest: () => dispatcher[0].delete(queueKey, req.requestId, abortKey) | ||
})); | ||
}; | ||
const getInitialState2 = () => { | ||
const [queue] = dispatcher; | ||
const commandQueue = queue.getQueue(queueKey); | ||
setStopped(commandQueue.stopped); | ||
setRequests(createRequestsArray(commandQueue.requests)); | ||
}; | ||
const mountEvents = () => { | ||
var _a; | ||
const [queue] = dispatcher; | ||
const unmountChange = queue.events.onQueueChange(queueKey, (values) => { | ||
setStopped(values.stopped); | ||
setRequests(createRequestsArray(values.requests)); | ||
}); | ||
const unmountDownload = commandManager.events.onDownloadProgress(queueKey, (progress, { requestId }) => { | ||
setRequests((prev) => prev.map((el) => el.requestId === requestId ? __spreadProps(__spreadValues({}, el), { downloading: progress }) : el)); | ||
}); | ||
const unmountUpload = commandManager.events.onDownloadProgress(queueKey, (progress, { requestId }) => { | ||
setRequests((prev) => prev.map((el) => el.requestId === requestId ? __spreadProps(__spreadValues({}, el), { uploading: progress }) : el)); | ||
}); | ||
const unmountStatus = queue.events.onQueueStatus(queueKey, (values) => { | ||
setStopped(values.stopped); | ||
setRequests(createRequestsArray(values.requests)); | ||
}); | ||
const unmount = () => { | ||
unmountStatus(); | ||
unmountChange(); | ||
unmountDownload(); | ||
unmountUpload(); | ||
}; | ||
(_a = unmountCallbacks.current) == null ? void 0 : _a.call(unmountCallbacks); | ||
unmountCallbacks.current = unmount; | ||
return unmount; | ||
}; | ||
useDidMount3(getInitialState2); | ||
useDidUpdate5(mountEvents, [stopped, requests, setRequests, setStopped], true); | ||
return { | ||
stopped, | ||
requests, | ||
stop: () => dispatcher[0].stop(queueKey), | ||
pause: () => dispatcher[0].pause(queueKey), | ||
start: () => dispatcher[0].start(queueKey) | ||
}; | ||
}; | ||
// src/use-queue/use-queue.constants.ts | ||
var useQueueDefaultOptions = { | ||
queueType: "auto" | ||
}; | ||
// src/use-cache/use-cache.hooks.ts | ||
import { useRef as useRef7 } from "react"; | ||
import { getCommandDispatcher as getCommandDispatcher2, Command as Command3, getCommandKey as getCommandKey3 } from "@better-typed/hyper-fetch"; | ||
var useCache = (command, { | ||
dependencyTracking = useCacheDefaultOptions.dependencyTracking, | ||
initialData = useCacheDefaultOptions.initialData, | ||
deepCompare = useCacheDefaultOptions.deepCompare | ||
} = useCacheDefaultOptions) => { | ||
const { cacheKey, builder } = command; | ||
const { cache, loggerManager } = builder; | ||
const logger = useRef7(loggerManager.init("useCache")).current; | ||
const [dispatcher] = getCommandDispatcher2(command); | ||
const [state, actions, { setRenderKey, setCacheData }] = useDependentState({ | ||
logger, | ||
command, | ||
dispatcher, | ||
initialData, | ||
deepCompare, | ||
dependencyTracking | ||
}); | ||
const [callbacks] = useCommandEvents({ | ||
state, | ||
logger, | ||
actions, | ||
command, | ||
dispatcher, | ||
setCacheData | ||
}); | ||
const revalidate = (revalidateKey) => { | ||
if (revalidateKey && revalidateKey instanceof Command3) { | ||
cache.events.revalidate(`/${getCommandKey3(revalidateKey, true)}/`); | ||
} else if (revalidateKey) { | ||
cache.events.revalidate(revalidateKey); | ||
} else { | ||
cache.events.revalidate(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 retries() { | ||
setRenderKey("retries"); | ||
return state.retries; | ||
}, | ||
get timestamp() { | ||
setRenderKey("timestamp"); | ||
return state.timestamp; | ||
}, | ||
onCacheError: callbacks.onError, | ||
onCacheSuccess: callbacks.onSuccess, | ||
onCacheChange: callbacks.onFinished | ||
}, actions), { | ||
revalidate | ||
}); | ||
}; | ||
// src/use-cache/use-cache.constants.ts | ||
var useCacheDefaultOptions = { | ||
dependencyTracking: true, | ||
initialData: null, | ||
deepCompare: true | ||
}; | ||
// src/use-app-manager/use-app-manager.hooks.ts | ||
import { useState as useState2 } from "react"; | ||
import { useDidMount as useDidMount4 } from "@better-typed/react-lifecycle-hooks"; | ||
var useAppManager = (builder) => { | ||
const [online, setIsOnline] = useState2(builder.appManager.isOnline); | ||
const [focused, setIsFocused] = useState2(builder.appManager.isFocused); | ||
const mountEvents = () => { | ||
const unmountIsOnline = builder.appManager.events.onOnline(() => setIsOnline(true)); | ||
const unmountIsOffline = builder.appManager.events.onOffline(() => setIsOnline(false)); | ||
const unmountIsFocus = builder.appManager.events.onFocus(() => setIsFocused(true)); | ||
const unmountIsBlur = builder.appManager.events.onBlur(() => setIsFocused(false)); | ||
return () => { | ||
unmountIsOnline(); | ||
unmountIsOffline(); | ||
unmountIsFocus(); | ||
unmountIsBlur(); | ||
}; | ||
}; | ||
const setOnline = (isOnline) => { | ||
builder.appManager.setOnline(isOnline); | ||
}; | ||
const setFocused = (isFocused) => { | ||
builder.appManager.setFocused(isFocused); | ||
}; | ||
useDidMount4(mountEvents); | ||
return { isOnline: online, isFocused: focused, setOnline, setFocused }; | ||
}; | ||
export { | ||
getDetailsState, | ||
getInitialState, | ||
getTimestamp, | ||
getValidCacheData, | ||
initialState, | ||
isEmpty, | ||
isEqual, | ||
isStaleCacheData, | ||
responseToCacheValue, | ||
useAppManager, | ||
useCache, | ||
useCacheDefaultOptions, | ||
useCommandEvents, | ||
useDebounce, | ||
useDependentState, | ||
useFetch, | ||
useFetchDefaultOptions, | ||
useQueue, | ||
useQueueDefaultOptions, | ||
useSubmit, | ||
useSubmitDefaultOptions | ||
}; | ||
var Se=Object.defineProperty,De=Object.defineProperties;var Oe=Object.getOwnPropertyDescriptors;var de=Object.getOwnPropertySymbols;var Ue=Object.prototype.hasOwnProperty,ke=Object.prototype.propertyIsEnumerable;var Te=(e,t,r)=>t in e?Se(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,k=(e,t)=>{for(var r in t||(t={}))Ue.call(t,r)&&Te(e,r,t[r]);if(de)for(var r of de(t))ke.call(t,r)&&Te(e,r,t[r]);return e},P=(e,t)=>De(e,Oe(t));var _=(e,t,r)=>new Promise((b,d)=>{var C=a=>{try{u(r.next(a))}catch(y){d(y)}},m=a=>{try{u(r.throw(a))}catch(y){d(y)}},u=a=>a.done?b(a.value):Promise.resolve(a.value).then(C,m);u((r=r.apply(e,t)).next())});import{useRef as Ke}from"react";import{useDidUpdate as ie,useDidMount as Qe}from"@better-typed/react-lifecycle-hooks";import{Command as be,getCommandKey as Be}from"@better-typed/hyper-fetch";import{useRef as L}from"react";import{getErrorMessage as ve}from"@better-typed/hyper-fetch";import{useIsMounted as qe,useWillUnmount as Fe}from"@better-typed/react-lifecycle-hooks";var H=({command:e,dispatcher:t,logger:r,actions:b,setCacheData:d})=>{let{cache:C,commandManager:m}=e.builder,u=qe(),a=L(null),y=L(null),T=L(null),h=L(null),R=L(null),s=L(null),O=L(null),x=L(null),g=L(null),f=L(new Map),v=L(null),M=n=>{let c=f.current.get(n);c==null||c.unmount(),f.current.delete(n)},A=()=>{let n=f.current;Array.from(n.values()).forEach(p=>{p.unmount()}),n.clear()},o=(n,c,p)=>{var $,G,J,D,Q;if(!u)return r.debug("Callback cancelled, component is unmounted");let{isOffline:F,isFailed:I,isCanceled:Y}=p;e.offline&&F&&I?(r.debug("Performing offline error callback",{data:c,details:p}),($=h.current)==null||$.call(h,{response:c[1],command:n,details:p})):Y?(r.debug("Performing abort callback",{data:c,details:p}),(G=T.current)==null||G.call(T,{response:c[1],command:n,details:p})):I?(r.debug("Performing error callback",{data:c,details:p}),(D=y.current)==null||D.call(y,{response:c[1],command:n,details:p})):(r.debug("Performing success callback",{data:c,details:p}),(J=a.current)==null||J.call(a,{response:c[0],command:n,details:p})),(Q=R.current)==null||Q.call(R,{response:c,command:n,details:p})},i=n=>({isLoading:c})=>{let p=!c&&!t.hasRunningRequests(n);(c||p)&&b.setLoading(c,!1)},l=(n,c)=>{var p;(p=x==null?void 0:x.current)==null||p.call(x,n,c)},U=(n,c)=>{var p;(p=g==null?void 0:g.current)==null||p.call(g,n,c)},E=n=>c=>{var p;(p=s==null?void 0:s.current)==null||p.call(s,{command:n,details:c})},S=n=>c=>{var p;(p=O==null?void 0:O.current)==null||p.call(O,{command:n,details:c})},K=n=>(c,p)=>{o(n,c,p)},w=({requestId:n})=>{M(n)},te=n=>()=>{let c=[null,ve("abort"),0],p={retries:0,timestamp:+new Date,isFailed:!1,isCanceled:!0,isOffline:!1};o(n,c,p)},B=()=>{var n;(n=v.current)==null||n.unmount(),v.current=null},re=n=>{let c=m.events.onLoading(n.queueKey,i(n.queueKey)),p=C.events.onData(n.cacheKey,d),F=m.events.onAbort(n.abortKey,te(n)),I=()=>{c(),p(),F()};return B(),v.current={unmount:I},I},se=(n,c)=>{if(!c){let{queueKey:D,cacheKey:Q}=n,Z=m.events.onRequestStart(D,E(n)),z=m.events.onResponseStart(D,S(n)),ae=m.events.onUploadProgress(D,U),le=m.events.onDownloadProgress(D,l),Ee=m.events.onResponse(Q,K(n)),me=()=>{le(),ae(),Z(),z(),Ee()};return f.current.set(D,{unmount:me}),me}let p=m.events.onRemoveById(c,w),F=m.events.onRequestStartById(c,E(n)),I=m.events.onResponseStartById(c,S(n)),Y=m.events.onResponseById(c,K(n)),$=m.events.onUploadProgressById(c,U),G=m.events.onDownloadProgressById(c,l),J=()=>{p(),G(),$(),F(),I(),Y()};return f.current.set(c,{unmount:J}),J},oe=()=>{let{abortKey:n}=e;t.getAllRunningRequest().forEach(p=>{p.command.abortKey===n&&t.delete(p.command.queueKey,p.requestId,n)})};return Fe(()=>{A(),B()}),[{abort:oe,onSuccess:n=>{a.current=n},onError:n=>{y.current=n},onAbort:n=>{T.current=n},onOfflineError:n=>{h.current=n},onFinished:n=>{R.current=n},onRequestStart:n=>{s.current=n},onResponseStart:n=>{O.current=n},onDownloadProgress:n=>{x.current=n},onUploadProgress:n=>{g.current=n}},{addDataListener:re,clearDataListener:B,addLifecycleListeners:se,removeLifecycleListener:M,clearLifecycleListeners:A}]};import{useRef as Ie}from"react";import{useWillUnmount as we,useDidUpdate as Me}from"@better-typed/react-lifecycle-hooks";var V=(e=600)=>{let t=Ie({time:e,timer:null});Me(()=>{t.current.time=e},[e]);let r=()=>{t.current.timer!==null&&clearTimeout(t.current.timer),t.current.timer=null},b=(d,C)=>{r(),t.current.timer=setTimeout(()=>{d()},C||t.current.time)};return we(r),{debounce:b,resetDebounce:r,active:!!t.current.timer}};var j={data:null,error:null,loading:!1,status:null,retries:0,timestamp:null};import{useRef as ye}from"react";import{useDidUpdate as ge,useForceUpdate as Ae}from"@better-typed/react-lifecycle-hooks";var fe=e=>{let t=Object.prototype.toString.call(e);return Array.isArray(e)?!e.length:typeof e=="object"&&e!==null&&t==="[object Object]"?!Object.keys(e).length:!1},ne=(e,t)=>{let r=Object.prototype.toString.call(e),b=Object.prototype.toString.call(t),d=typeof e,C=typeof t,m=a=>d===a&&C===a,u=a=>r===a&&b===a;return r!==b?!1:e===null&&t===null||m("number")&&Number.isNaN(e)&&Number.isNaN(t)||fe(e)&&fe(t)?!0:Array.isArray(e)&&Array.isArray(t)?e.length!==t.length?!1:!e.some((a,y)=>!ne(a,t[y])):m("object")&&u("[object Object]")?Object.keys(e).length!==Object.keys(t).length?!1:!Object.entries(e).some(([a,y])=>!ne(y,t[a])):e instanceof Date&&t instanceof Date?+e==+t:e===t};var N=(e,t)=>k({retries:(e==null?void 0:e.retries)||0,timestamp:+new Date,isFailed:!1,isCanceled:!1,isOffline:!1},t),ue=(e,t)=>t?e?+new Date>+t+e:!1:!0,Pe=(e,t,r)=>!ue(e.cacheTime,r==null?void 0:r.details.timestamp)&&r?r:t?{data:t,details:N(),cacheTime:1e3,clearKey:e.builder.cache.clearKey}:null,Le=e=>e?new Date(e):null,Ut=e=>e?{data:e,details:N(),cacheTime:1e3,clearKey:""}:null,ce=(e,t,r)=>{var y,T,h;let{builder:b,cacheKey:d}=r,{cache:C}=b,m=C.get(d),u=Pe(r,e,m),a=t.hasRunningRequests(r.queueKey);return P(k({},j),{data:((y=u==null?void 0:u.data)==null?void 0:y[0])||j.data,error:((T=u==null?void 0:u.data)==null?void 0:T[1])||j.error,status:((h=u==null?void 0:u.data)==null?void 0:h[2])||j.status,retries:(u==null?void 0:u.details.retries)||j.retries,timestamp:Le((u==null?void 0:u.details.timestamp)||j.timestamp),loading:a!=null?a:j.loading})};var X=({command:e,dispatcher:t,initialData:r,deepCompare:b,dependencyTracking:d,defaultCacheEmitting:C=!0})=>{let{builder:m,cacheKey:u,queueKey:a,cacheTime:y}=e,{cache:T,commandManager:h}=m,R=Ae(),s=ye(ce(r,t,e)),O=ye([]),x=()=>{var i;let o=T.get(u);return ue(y,(o==null?void 0:o.details.timestamp)||((i=s.current)==null?void 0:i.timestamp))},g=o=>{O.current.some(l=>o.includes(l))&&R()},f=o=>{O.current.includes(o)||O.current.push(o)};ge(()=>{s.current.loading=t.hasRunningRequests(a);let o=ce(r,t,e),i=(r==null?void 0:r[0])===s.current.data,l=!!(s.current.data||s.current.error)&&!i,U=!l&&s.current.data,E=l&&!s.current.data;(U||E)&&(s.current=o)},[u,a],!0),ge(()=>{(()=>{d||Object.keys(s.current).forEach(i=>f(i))})()},[d],!0);let v=(o,i)=>typeof b=="function"?b(o,i):b?ne(o,i):!1,M=o=>_(void 0,null,function*(){let i={data:o.data[0],error:o.data[1],status:o.data[2],retries:o.details.retries,timestamp:new Date(o.details.timestamp),loading:s.current.loading},l=Object.keys(i).filter(U=>{let E=U,S=s.current[E],K=i[E];return!v(S,K)});s.current=k(k({},s.current),i),g(l)}),A={setData:(o,i=C)=>{if(i){let l=s.current;T.set(e,[o,l.error,l.status],N(s.current))}else s.current.data=o,g(["data"])},setError:(o,i=C)=>{if(i){let l=s.current;T.set(e,[l.data,o,l.status],N(s.current,{isFailed:!!o}))}else s.current.error=o,g(["error"])},setLoading:(o,i=!0)=>{i?h.events.emitLoading(a,"",{queueKey:a,requestId:"",isLoading:o,isRetry:!1,isOffline:!1}):(s.current.loading=o,g(["loading"]))},setStatus:(o,i=C)=>{if(i){let l=s.current;T.set(e,[l.data,l.error,o],N(s.current))}else s.current.status=o,g(["status"])},setRetries:(o,i=C)=>{if(i){let l=s.current;T.set(e,[l.data,l.error,l.status],N(s.current,{retries:o}))}else s.current.retries=o,g(["retries"])},setTimestamp:(o,i=C)=>{if(i){let l=s.current;T.set(e,[l.data,l.error,l.status],N(s.current,{timestamp:+o}))}else s.current.timestamp=o,g(["timestamp"])}};return[s.current,A,{setRenderKey:f,setCacheData:M,getStaleStatus:x}]};var Zt=(e,{dependencies:t=q.dependencies,disabled:r=q.disabled,dependencyTracking:b=q.dependencyTracking,revalidateOnMount:d=q.revalidateOnMount,initialData:C=q.initialData,refresh:m=q.refresh,refreshTime:u=q.refreshTime,refreshBlurred:a=q.refreshBlurred,refreshOnTabBlur:y=q.refreshOnTabBlur,refreshOnTabFocus:T=q.refreshOnTabFocus,refreshOnReconnect:h=q.refreshOnReconnect,debounce:R=q.debounce,debounceTime:s=q.debounceTime,deepCompare:O=q.deepCompare}=q)=>{let x=JSON.stringify(e.dump()),g=V(s),f=V(u),{cacheKey:v,queueKey:M,builder:A}=e,{cache:o,fetchDispatcher:i,appManager:l,loggerManager:U}=A,E=Ke(U.init("useFetch")).current,[S,K,{setRenderKey:w,setCacheData:te,getStaleStatus:B}]=X({logger:E,command:e,dispatcher:i,initialData:C,deepCompare:O,dependencyTracking:b}),[re,se]=H({logger:E,actions:K,command:e,dispatcher:i,setCacheData:te}),{addDataListener:oe,addLifecycleListeners:n,clearDataListener:c,clearLifecycleListeners:p}=se,F=()=>{r?E.debug("Cannot add to fetch queue",{disabled:r}):(E.debug("Fetching data"),i.add(e))};function I(){!m||(E.debug(`Starting refresh counter, request will be send in ${u}ms`),f.debounce(()=>{let D=!l.isFocused,Q=i.hasRunningRequests(e.queueKey),Z=i.getIsActiveQueue(e.queueKey),z=Q||Z;(D&&a&&!z||!D&&!z)&&(F(),E.debug("Performing refresh request")),I()}))}let Y=D=>{D&&D instanceof be?o.revalidate(Be(D)):D&&!(D instanceof be)?o.revalidate(D):(F(),I())},$=()=>{let D=B(),Q=i.getIsActiveQueue(M);(d||D&&!Q)&&F()},G=()=>{R?(E.debug("Debouncing request",{queueKey:M,command:e}),g.debounce(()=>F())):F()};return ie(()=>{oe(e),n(e);let D=l.events.onFocus(()=>{T&&(F(),I())}),Q=l.events.onBlur(()=>{y&&(F(),I())}),Z=l.events.onOnline(()=>{h&&(F(),I())}),z=o.events.onRevalidate(v,F);return()=>{c(),p(),D(),Q(),Z(),z()}},[x],!0),Qe($),ie(G,[x,...t]),ie(I,[x,...t,r,m,u],!0),P(k(k({get data(){return w("data"),S.data},get error(){return w("error"),S.error},get loading(){return w("loading"),S.loading},get status(){return w("status"),S.status},get retries(){return w("retries"),S.retries},get timestamp(){return w("timestamp"),S.timestamp}},K),re),{isDebouncing:g.active,revalidate:Y})};import{DateInterval as je}from"@better-typed/hyper-fetch";var q={dependencies:[],disabled:!1,dependencyTracking:!0,revalidateOnMount:!0,initialData:null,refresh:!1,refreshTime:je.hour,refreshBlurred:!0,refreshOnTabBlur:!1,refreshOnTabFocus:!1,refreshOnReconnect:!1,debounce:!1,debounceTime:400,deepCompare:!0};import{useRef as Ne}from"react";import{Command as Ce,getCommandKey as We,commandSendRequest as $e}from"@better-typed/hyper-fetch";import{useDidMount as Ge}from"@better-typed/react-lifecycle-hooks";var gn=(e,{disabled:t=W.disabled,dependencyTracking:r=W.dependencyTracking,initialData:b=W.initialData,debounce:d=W.debounce,debounceTime:C=W.debounceTime,deepCompare:m=W.deepCompare}=W)=>{let{builder:u}=e,{cache:a,submitDispatcher:y,loggerManager:T}=u,h=Ne(T.init("useSubmit")).current,R=V(C),[s,O,{setRenderKey:x,setCacheData:g}]=X({logger:h,command:e,dispatcher:y,initialData:b,deepCompare:m,dependencyTracking:r}),[f,v]=H({logger:h,actions:O,command:e,dispatcher:y,setCacheData:g}),{addDataListener:M,addLifecycleListeners:A}=v,o=(...U)=>{let E=U[0],S=e.clone(E);if(t)return h.warning("Cannot submit request",{disabled:t,options:E}),[null,null,0];let K=()=>(M(S),$e(S,"submit",w=>{A(S,w)}));return new Promise(w=>{(()=>_(void 0,null,function*(){if(h.debug("Submitting request",{disabled:t,options:E}),d)R.debounce(()=>_(void 0,null,function*(){let B=yield K();w(B)}));else{let B=yield K();w(B)}}))()})},i=U=>{!U||(U&&U instanceof Ce?a.revalidate(We(U)):U instanceof Ce||a.revalidate(U))},l={onSubmitSuccess:f.onSuccess,onSubmitError:f.onError,onSubmitFinished:f.onFinished,onSubmitRequestStart:f.onRequestStart,onSubmitResponseStart:f.onResponseStart,onSubmitDownloadProgress:f.onDownloadProgress,onSubmitUploadProgress:f.onUploadProgress,onSubmitOfflineError:f.onOfflineError,onSubmitAbort:f.onAbort};return Ge(()=>{M(e)}),P(k(k({submit:o,get data(){return x("data"),s.data},get error(){return x("error"),s.error},get submitting(){return x("loading"),s.loading},get status(){return x("status"),s.status},get retries(){return x("retries"),s.retries},get timestamp(){return x("timestamp"),s.timestamp},abort:f.abort},O),l),{isDebouncing:R.active,revalidate:i})};var W={disabled:!1,dependencyTracking:!0,cacheOnMount:!0,initialData:null,debounce:!1,debounceTime:400,suspense:!1,shouldThrow:!1,invalidate:[],deepCompare:!0};import{useState as he,useRef as Je}from"react";import{getCommandDispatcher as ze}from"@better-typed/hyper-fetch";import{useDidMount as He,useDidUpdate as Xe}from"@better-typed/react-lifecycle-hooks";var wn=(e,t=pe)=>{let{queueType:r=pe.queueType}=t,{abortKey:b,queueKey:d,builder:C}=e,{commandManager:m}=C,[u]=ze(e,r),a=Je(null),[y,T]=he(!1),[h,R]=he([]),s=f=>f.map(v=>P(k({},v),{stopRequest:()=>u[0].stopRequest(d,v.requestId),startRequest:()=>u[0].startRequest(d,v.requestId),deleteRequest:()=>u[0].delete(d,v.requestId,b)})),O=()=>{let f=u.getQueue(d);T(f.stopped),R(s(f.requests))},x=f=>{T(f.stopped),R(s(f.requests))},g=()=>{var i;let f=u.events.onQueueChange(d,x),v=u.events.onQueueStatus(d,x),M=m.events.onDownloadProgress(d,(l,{requestId:U})=>{R(E=>E.map(S=>S.requestId===U?P(k({},S),{downloading:l}):S))}),A=m.events.onUploadProgress(d,(l,{requestId:U})=>{R(E=>E.map(S=>S.requestId===U?P(k({},S),{uploading:l}):S))}),o=()=>{v(),f(),M(),A()};return(i=a.current)==null||i.call(a),a.current=o,o};return He(O),Xe(g,[y,h,R,T],!0),{stopped:y,requests:h,stop:()=>u[0].stop(d),pause:()=>u[0].pause(d),start:()=>u[0].start(d)}};var pe={queueType:"auto"};import{useRef as Ye}from"react";import{getCommandDispatcher as Ze,Command as Re,getCommandKey as _e}from"@better-typed/hyper-fetch";var zn=(e,{dependencyTracking:t=ee.dependencyTracking,initialData:r=ee.initialData,deepCompare:b=ee.deepCompare}=ee)=>{let{cacheKey:d,builder:C}=e,{cache:m,loggerManager:u}=C,a=Ye(u.init("useCache")).current,[y]=Ze(e),[T,h,{setRenderKey:R,setCacheData:s}]=X({logger:a,command:e,dispatcher:y,initialData:r,deepCompare:b,dependencyTracking:t}),[O]=H({logger:a,actions:h,command:e,dispatcher:y,setCacheData:s}),x=g=>{g&&g instanceof Re?m.revalidate(`/${_e(g,!0)}/`):g&&!(g instanceof Re)?m.revalidate(g):m.revalidate(d)};return P(k({get data(){return R("data"),T.data},get error(){return R("error"),T.error},get loading(){return R("loading"),T.loading},get status(){return R("status"),T.status},get retries(){return R("retries"),T.retries},get timestamp(){return R("timestamp"),T.timestamp},onCacheError:O.onError,onCacheSuccess:O.onSuccess,onCacheChange:O.onFinished},h),{revalidate:x})};var ee={dependencyTracking:!0,initialData:null,deepCompare:!0};import{useState as xe}from"react";import{useDidMount as Ve}from"@better-typed/react-lifecycle-hooks";var nr=e=>{let[t,r]=xe(e.appManager.isOnline),[b,d]=xe(e.appManager.isFocused),C=()=>{let a=e.appManager.events.onOnline(()=>r(!0)),y=e.appManager.events.onOffline(()=>r(!1)),T=e.appManager.events.onFocus(()=>d(!0)),h=e.appManager.events.onBlur(()=>d(!1));return()=>{a(),y(),T(),h()}},m=a=>{e.appManager.setOnline(a)},u=a=>{e.appManager.setFocused(a)};return Ve(C),{isOnline:t,isFocused:b,setOnline:m,setFocused:u}};export{X as UseTrackedState,N as getDetailsState,ce as getInitialState,Le as getTimestamp,Pe as getValidCacheData,j as initialState,fe as isEmpty,ne as isEqual,ue as isStaleCacheData,Ut as responseToCacheValue,nr as useAppManager,zn as useCache,ee as useCacheDefaultOptions,H as useCommandEvents,V as useDebounce,Zt as useFetch,q as useFetchDefaultOptions,wn as useQueue,pe as useQueueDefaultOptions,gn as useSubmit,W as useSubmitDefaultOptions}; | ||
//# sourceMappingURL=index.esm.js.map |
@@ -1,6 +0,3 @@ | ||
export declare const useAppManager: <B extends Builder<any, any>>(builder: B) => { | ||
isOnline: any; | ||
isFocused: any; | ||
setOnline: (isOnline: boolean) => void; | ||
setFocused: (isFocused: boolean) => void; | ||
}; | ||
import { BuilderInstance } from "@better-typed/hyper-fetch"; | ||
import { UseAppManagerReturnType } from "./"; | ||
export declare const useAppManager: <B extends BuilderInstance>(builder: B) => UseAppManagerReturnType; |
export declare type UseAppManagerReturnType = { | ||
/** | ||
* Is window focused | ||
*/ | ||
isFocused: boolean; | ||
/** | ||
* Network online status | ||
*/ | ||
isOnline: boolean; | ||
/** | ||
* Network state setter | ||
*/ | ||
setOnline: (isOnline: boolean) => void; | ||
/** | ||
* Focus state setter | ||
*/ | ||
setFocused: (isFocused: boolean) => void; | ||
}; |
import { CommandInstance } from "@better-typed/hyper-fetch"; | ||
import { UseCacheOptionsType } from "use-cache"; | ||
export declare const useCache: <T extends Command<any, any, any, any, any, any, any, any, any, any, any>>(command: T, { dependencyTracking, initialData, deepCompare, }?: UseCacheOptionsType<T>) => { | ||
revalidate: (revalidateKey?: string | CommandInstance | RegExp) => void; | ||
setData: (data: import("@better-typed/hyper-fetch").ExtractResponse<T>, emitToCache?: boolean) => void; | ||
setError: (error: import("@better-typed/hyper-fetch").ExtractError<T>, emitToCache?: boolean) => void; | ||
setLoading: (loading: boolean, emitToHooks?: boolean) => void; | ||
setStatus: (status: number, emitToCache?: boolean) => void; | ||
setRetries: (retries: number, emitToCache?: boolean) => void; | ||
setTimestamp: (timestamp: Date, emitToCache?: boolean) => void; | ||
data: import("@better-typed/hyper-fetch").ExtractResponse<T>; | ||
error: import("@better-typed/hyper-fetch").ExtractError<T>; | ||
loading: boolean; | ||
status: number; | ||
retries: number; | ||
timestamp: Date; | ||
onCacheError: (callback: import("helpers").OnErrorCallbackType<T>) => void; | ||
onCacheSuccess: (callback: import("helpers").OnSuccessCallbackType<T>) => void; | ||
onCacheChange: (callback: import("helpers").OnFinishedCallbackType<T>) => void; | ||
}; | ||
import { UseCacheOptionsType, UseCacheReturnType } from "./"; | ||
export declare const useCache: <T extends CommandInstance>(command: T, { dependencyTracking, initialData, deepCompare, }?: UseCacheOptionsType<T>) => UseCacheReturnType<T>; |
import { CommandInstance, ExtractResponse, ExtractError, CacheValueType } from "@better-typed/hyper-fetch"; | ||
import { isEqual } from "utils"; | ||
import { OnErrorCallbackType, OnFinishedCallbackType, OnSuccessCallbackType, UseDependentStateActions, UseDependentStateType } from "helpers"; | ||
import { isEqual } from "../utils"; | ||
import { OnErrorCallbackType, OnFinishedCallbackType, OnSuccessCallbackType, UseTrackedStateActions, UseTrackedStateType } from "../helpers"; | ||
export declare type UseCacheOptionsType<T extends CommandInstance> = { | ||
/** | ||
* If `true` it will rerender only when values used by our component gets changed. Otherwise it will rerender on any change. | ||
*/ | ||
dependencyTracking?: boolean; | ||
/** | ||
* If cache is empty we can use placeholder data. | ||
*/ | ||
initialData?: CacheValueType<ExtractResponse<T>, ExtractError<T>>["data"] | null; | ||
/** | ||
* Deep comparison function for hook to check for equality in incoming data, to limit rerenders. | ||
*/ | ||
deepCompare?: boolean | typeof isEqual; | ||
}; | ||
export declare type UseCacheReturnType<T extends CommandInstance> = UseDependentStateType<T> & { | ||
actions: UseDependentStateActions<T>; | ||
export declare type UseCacheReturnType<T extends CommandInstance> = UseTrackedStateType<T> & UseTrackedStateActions<T> & { | ||
/** | ||
* Helper hook listener for success response | ||
*/ | ||
onCacheSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
/** | ||
* Helper hook listener for error response | ||
*/ | ||
onCacheError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listener for response | ||
*/ | ||
onCacheChange: (callback: OnFinishedCallbackType<T>) => void; | ||
isStale: boolean; | ||
isRefreshingError: boolean; | ||
revalidate: (revalidateKey?: string | CommandInstance) => void; | ||
/** | ||
* Revalidate current command resource or pass custom key to trigger it by invalidationKey(Regex / cacheKey). | ||
*/ | ||
revalidate: (invalidateKey?: string | CommandInstance) => void; | ||
}; |
import { CommandInstance, RequiredKeys } from "@better-typed/hyper-fetch"; | ||
import { UseFetchOptionsType } from "use-fetch"; | ||
import { UseFetchOptionsType } from "./"; | ||
declare type DefaultOptionsType = RequiredKeys<Omit<UseFetchOptionsType<CommandInstance>, "initialData">> & { | ||
@@ -4,0 +4,0 @@ initialData: null; |
import { CommandInstance } from "@better-typed/hyper-fetch"; | ||
import { UseFetchOptionsType } from "use-fetch"; | ||
import { UseFetchOptionsType, UseFetchReturnType } from "./"; | ||
/** | ||
@@ -9,27 +9,2 @@ * This hooks aims to retrieve data from server. | ||
*/ | ||
export declare const useFetch: <T extends Command<any, any, any, any, any, any, any, any, any, any, any>>(command: T, { dependencies, disabled, dependencyTracking, revalidateOnMount, initialData, refresh, refreshTime, refreshBlurred, refreshOnTabBlur, refreshOnTabFocus, refreshOnReconnect, debounce, debounceTime, deepCompare, }?: UseFetchOptionsType<T>) => { | ||
isDebouncing: boolean; | ||
revalidate: (invalidateKey?: string | CommandInstance | RegExp) => void; | ||
abort: () => void; | ||
onSuccess: (callback: import("helpers").OnSuccessCallbackType<T>) => void; | ||
onError: (callback: import("helpers").OnErrorCallbackType<T>) => void; | ||
onAbort: (callback: import("helpers").OnErrorCallbackType<T>) => void; | ||
onOfflineError: (callback: import("helpers").OnErrorCallbackType<T>) => void; | ||
onFinished: (callback: import("helpers").OnFinishedCallbackType<T>) => void; | ||
onRequestStart: (callback: import("helpers").OnStartCallbackType<T>) => void; | ||
onResponseStart: (callback: import("helpers").OnStartCallbackType<T>) => void; | ||
onDownloadProgress: (callback: import("helpers").OnProgressCallbackType) => void; | ||
onUploadProgress: (callback: import("helpers").OnProgressCallbackType) => void; | ||
setData: (data: import("@better-typed/hyper-fetch").ExtractResponse<T>, emitToCache?: boolean) => void; | ||
setError: (error: import("@better-typed/hyper-fetch").ExtractError<T>, emitToCache?: boolean) => void; | ||
setLoading: (loading: boolean, emitToHooks?: boolean) => void; | ||
setStatus: (status: number, emitToCache?: boolean) => void; | ||
setRetries: (retries: number, emitToCache?: boolean) => void; | ||
setTimestamp: (timestamp: Date, emitToCache?: boolean) => void; | ||
data: import("@better-typed/hyper-fetch").ExtractResponse<T>; | ||
error: import("@better-typed/hyper-fetch").ExtractError<T>; | ||
loading: boolean; | ||
status: number; | ||
retries: number; | ||
timestamp: Date; | ||
}; | ||
export declare const useFetch: <T extends CommandInstance>(command: T, { dependencies, disabled, dependencyTracking, revalidateOnMount, initialData, refresh, refreshTime, refreshBlurred, refreshOnTabBlur, refreshOnTabFocus, refreshOnReconnect, debounce, debounceTime, deepCompare, }?: UseFetchOptionsType<T>) => UseFetchReturnType<T>; |
import { CommandInstance, ExtractResponse, ExtractError, CacheValueType } from "@better-typed/hyper-fetch"; | ||
import { OnErrorCallbackType, OnFinishedCallbackType, OnProgressCallbackType, OnStartCallbackType, OnSuccessCallbackType, UseDependentStateActions, UseDependentStateType } from "helpers"; | ||
import { isEqual } from "utils"; | ||
import { UseCommandEventsActionsType, UseTrackedStateActions, UseTrackedStateType } from "../helpers"; | ||
import { isEqual } from "../utils"; | ||
export declare type UseFetchOptionsType<T extends CommandInstance> = { | ||
/** | ||
* Refetch dependencies | ||
*/ | ||
dependencies?: any[]; | ||
/** | ||
* Disable fetching | ||
*/ | ||
disabled?: boolean; | ||
/** | ||
* If `true` it will rerender only when values used by our component gets changed. Otherwise it will rerender on any change. | ||
*/ | ||
dependencyTracking?: boolean; | ||
/** | ||
* If `true` it will refetch data in background no matter if we have it from cache. | ||
*/ | ||
revalidateOnMount?: boolean; | ||
/** | ||
* If cache is empty we can use placeholder data. | ||
*/ | ||
initialData?: CacheValueType<ExtractResponse<T>, ExtractError<T>>["data"] | null; | ||
/** | ||
* Enable/disable refresh data | ||
*/ | ||
refresh?: boolean; | ||
/** | ||
* Refresh data interval time | ||
*/ | ||
refreshTime?: number; | ||
/** | ||
* Enable/disable data refresh if our tab is not focused(used by user at given time). | ||
*/ | ||
refreshBlurred?: boolean; | ||
/** | ||
* Enable/disable data refresh if user leaves current tab. | ||
*/ | ||
refreshOnTabBlur?: boolean; | ||
/** | ||
* Enable/disable data refresh if user enters current tab. | ||
*/ | ||
refreshOnTabFocus?: boolean; | ||
/** | ||
* Enable/disable data refresh if network is restored. | ||
*/ | ||
refreshOnReconnect?: boolean; | ||
/** | ||
* Enable/disable debouncing for often changing keys or refreshing, to limit requests to server. | ||
*/ | ||
debounce?: boolean; | ||
/** | ||
* How long it should debounce requests. | ||
*/ | ||
debounceTime?: number; | ||
/** | ||
* Deep comparison function for hook to check for equality in incoming data, to limit rerenders. | ||
*/ | ||
deepCompare?: boolean | typeof isEqual; | ||
}; | ||
export declare type UseFetchReturnType<T extends CommandInstance> = UseDependentStateType<T> & { | ||
actions: UseDependentStateActions<T>; | ||
onSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
onError: (callback: OnErrorCallbackType<T>) => void; | ||
onFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
onRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
onResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
onDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
onUploadProgress: (callback: OnProgressCallbackType) => void; | ||
isRefreshed: boolean; | ||
isRefreshingError: boolean; | ||
export declare type UseFetchReturnType<T extends CommandInstance> = UseTrackedStateType<T> & UseTrackedStateActions<T> & UseCommandEventsActionsType<T> & { | ||
/** | ||
* Is debounce active at given moment | ||
*/ | ||
isDebouncing: boolean; | ||
isStale: boolean; | ||
/** | ||
* Revalidate current command resource or pass custom key to trigger it by invalidationKey(Regex / cacheKey). | ||
*/ | ||
revalidate: (invalidateKey?: string | CommandInstance) => void; | ||
abort: VoidFunction; | ||
}; |
import { RequiredKeys } from "@better-typed/hyper-fetch"; | ||
import { UseQueueOptions } from "use-queue"; | ||
export declare const useQueueDefaultOptions: RequiredKeys<UseQueueOptions>; | ||
import { UseQueueOptionsType } from "./"; | ||
export declare const useQueueDefaultOptions: RequiredKeys<UseQueueOptionsType>; |
@@ -1,2 +0,3 @@ | ||
import { UseQueueOptions, QueueRequest } from "use-queue"; | ||
import { CommandInstance } from "@better-typed/hyper-fetch"; | ||
import { UseQueueOptionsType, UseQueueReturnType } from "./"; | ||
/** | ||
@@ -8,8 +9,2 @@ * This hook allows to control dispatchers request queues | ||
*/ | ||
export declare const useQueue: <Command extends Command<any, any, any, any, any, any, any, any, any, any, any>>(command: Command, options?: UseQueueOptions) => { | ||
stopped: boolean; | ||
requests: QueueRequest<Command>[]; | ||
stop: () => any; | ||
pause: () => any; | ||
start: () => any; | ||
}; | ||
export declare const useQueue: <Command extends CommandInstance>(command: Command, options?: UseQueueOptionsType) => UseQueueReturnType<Command>; |
import { FetchProgressType, CommandInstance, DispatcherDumpValueType } from "@better-typed/hyper-fetch"; | ||
export declare type UseQueueOptions = { | ||
export declare type UseQueueOptionsType = { | ||
queueType?: "auto" | "fetch" | "submit"; | ||
}; | ||
export declare type QueueRequest<Command extends CommandInstance> = DispatcherDumpValueType<Command> & { | ||
/** | ||
* Uploading progress for given request | ||
*/ | ||
uploading?: FetchProgressType; | ||
/** | ||
* Downloading progress for given request | ||
*/ | ||
downloading?: FetchProgressType; | ||
/** | ||
* Callback which allow to start previously stopped request. | ||
*/ | ||
startRequest: () => void; | ||
/** | ||
* Callback which allow to stop request and cancel it if it's ongoing. | ||
*/ | ||
stopRequest: () => void; | ||
/** | ||
* Removes request from the queue | ||
*/ | ||
deleteRequest: () => void; | ||
}; | ||
export declare type UseQueueReturnType<T extends CommandInstance> = { | ||
/** | ||
* Queue status for provided command | ||
*/ | ||
stopped: boolean; | ||
/** | ||
* List of requests for provided command | ||
*/ | ||
requests: QueueRequest<T>[]; | ||
/** | ||
* Callback which allow to stop queue, it will cancel ongoing requests. | ||
*/ | ||
stop: () => void; | ||
/** | ||
* Callback which allow to pause queue. It will allow ongoing requests to be finished, but will stop next from being send. | ||
*/ | ||
pause: () => void; | ||
/** | ||
* Callback which allow to start queue. | ||
*/ | ||
start: () => void; | ||
}; |
import { CommandInstance } from "@better-typed/hyper-fetch"; | ||
import { UseSubmitOptionsType } from "use-submit"; | ||
import { UseSubmitOptionsType, UseSubmitReturnType } from "./"; | ||
/** | ||
@@ -9,29 +9,2 @@ * This hooks aims to mutate data on the server. | ||
*/ | ||
export declare const useSubmit: <T extends Command<any, any, any, any, any, any, any, any, any, any, any>>(command: T, { disabled, dependencyTracking, initialData, debounce, debounceTime, deepCompare, }?: UseSubmitOptionsType<T>) => { | ||
isDebouncing: boolean; | ||
isRefreshed: boolean; | ||
revalidate: (invalidateKey: string | CommandInstance | RegExp) => void; | ||
onSubmitSuccess: (callback: import("helpers").OnSuccessCallbackType<T>) => void; | ||
onSubmitError: (callback: import("helpers").OnErrorCallbackType<T>) => void; | ||
onSubmitFinished: (callback: import("helpers").OnFinishedCallbackType<T>) => void; | ||
onSubmitRequestStart: (callback: import("helpers").OnStartCallbackType<T>) => void; | ||
onSubmitResponseStart: (callback: import("helpers").OnStartCallbackType<T>) => void; | ||
onSubmitDownloadProgress: (callback: import("helpers").OnProgressCallbackType) => void; | ||
onSubmitUploadProgress: (callback: import("helpers").OnProgressCallbackType) => void; | ||
onSubmitOfflineError: (callback: import("helpers").OnErrorCallbackType<T>) => void; | ||
onSubmitAbort: (callback: import("helpers").OnErrorCallbackType<T>) => void; | ||
setData: (data: import("@better-typed/hyper-fetch").ExtractResponse<T>, emitToCache?: boolean) => void; | ||
setError: (error: import("@better-typed/hyper-fetch").ExtractError<T>, emitToCache?: boolean) => void; | ||
setLoading: (loading: boolean, emitToHooks?: boolean) => void; | ||
setStatus: (status: number, emitToCache?: boolean) => void; | ||
setRetries: (retries: number, emitToCache?: boolean) => void; | ||
setTimestamp: (timestamp: Date, emitToCache?: boolean) => void; | ||
submit: (...parameters: Parameters<T["send"]>) => number[] | Promise<any>; | ||
data: import("@better-typed/hyper-fetch").ExtractResponse<T>; | ||
error: import("@better-typed/hyper-fetch").ExtractError<T>; | ||
submitting: boolean; | ||
status: number; | ||
retries: number; | ||
timestamp: Date; | ||
abort: () => void; | ||
}; | ||
export declare const useSubmit: <T extends CommandInstance>(command: T, { disabled, dependencyTracking, initialData, debounce, debounceTime, deepCompare, }?: UseSubmitOptionsType<T>) => UseSubmitReturnType<T>; |
import { CacheValueType, ExtractError, ExtractResponse, CommandInstance } from "@better-typed/hyper-fetch"; | ||
import { isEqual } from "utils"; | ||
import { OnErrorCallbackType, OnFinishedCallbackType, OnProgressCallbackType, OnStartCallbackType, OnSuccessCallbackType, UseDependentStateType, UseDependentStateActions } from "helpers"; | ||
import { isEqual } from "../utils"; | ||
import { OnErrorCallbackType, OnFinishedCallbackType, OnProgressCallbackType, OnStartCallbackType, OnSuccessCallbackType, UseTrackedStateType, UseTrackedStateActions } from "../helpers"; | ||
export declare type UseSubmitOptionsType<T extends CommandInstance> = { | ||
/** | ||
* Disable fetching | ||
*/ | ||
disabled?: boolean; | ||
invalidate?: (string | CommandInstance)[]; | ||
cacheOnMount?: boolean; | ||
/** | ||
* If cache is empty we can use placeholder data. | ||
*/ | ||
initialData?: CacheValueType<ExtractResponse<T>, ExtractError<T>>["data"] | null; | ||
/** | ||
* Enable/disable debouncing for often changing keys or refreshing, to limit requests to server. | ||
*/ | ||
debounce?: boolean; | ||
/** | ||
* How long it should debounce requests. | ||
*/ | ||
debounceTime?: number; | ||
suspense?: boolean; | ||
shouldThrow?: boolean; | ||
/** | ||
* If `true` it will rerender only when values used by our component gets changed. Otherwise it will rerender on any change. | ||
*/ | ||
dependencyTracking?: boolean; | ||
/** | ||
* Deep comparison function for hook to check for equality in incoming data, to limit rerenders. | ||
*/ | ||
deepCompare?: boolean | typeof isEqual; | ||
}; | ||
export declare type UseSubmitReturnType<T extends CommandInstance> = Omit<UseDependentStateType<T>, "loading"> & { | ||
actions: UseDependentStateActions<T>; | ||
export declare type UseSubmitReturnType<T extends CommandInstance> = Omit<UseTrackedStateType<T>, "loading"> & UseTrackedStateActions<T> & { | ||
/** | ||
* Callback which allows to cancel ongoing requests from given queueKey. | ||
*/ | ||
abort: () => void; | ||
/** | ||
* Helper hook listening on success response. | ||
*/ | ||
onSubmitSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on error response. | ||
*/ | ||
onSubmitError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on any response. | ||
*/ | ||
onSubmitFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on request start. | ||
*/ | ||
onSubmitRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on response start(before we receive all data from server). | ||
*/ | ||
onSubmitResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on download progress ETA. We can later match given requests by their id's or command instance which holds all data which is being transferred. | ||
*/ | ||
onSubmitDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
/** | ||
* Helper hook listening on upload progress ETA. We can later match given requests by their id's or command instance which holds all data which is being transferred. | ||
*/ | ||
onSubmitUploadProgress: (callback: OnProgressCallbackType) => void; | ||
/** | ||
* Helper hook listening on aborting of requests. Abort events are not triggering onError callbacks. | ||
*/ | ||
onSubmitAbort: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on request going into offline awaiting for network connection to be restored. It will not trigger onError when 'offline' mode is set on command. | ||
*/ | ||
onSubmitOfflineError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Method responsible for triggering requests. It return Promise which will be resolved with the request. | ||
*/ | ||
submit: (...parameters: Parameters<T["send"]>) => void; | ||
/** | ||
* Request loading state | ||
*/ | ||
submitting: boolean; | ||
abort: VoidFunction; | ||
isStale: boolean; | ||
/** | ||
* Is debounce active at given moment | ||
*/ | ||
isDebouncing: boolean; | ||
revalidate: (revalidateKey: string | CommandInstance | RegExp) => void; | ||
/** | ||
* Revalidate current command resource or pass custom key to trigger it by invalidationKey(Regex / cacheKey). | ||
*/ | ||
revalidate: (invalidateKey: string | CommandInstance | RegExp) => void; | ||
}; |
@@ -10,2 +10,3 @@ import type { Config } from "@jest/types"; | ||
coverageProvider: "v8", | ||
coverageReporters: [["lcov", { projectRoot: "../.." }], "clover", "json", "text"], | ||
collectCoverageFrom: ["<rootDir>/src/**/*.ts", "<rootDir>/src/**/*.tsx"], | ||
@@ -12,0 +13,0 @@ coveragePathIgnorePatterns: [".spec", "test", "tests", "types", "constants", "index.ts"], |
{ | ||
"name": "@better-typed/react-hyper-fetch", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"private": false, | ||
@@ -20,6 +20,7 @@ "description": "React hooks and utils for the hyper-fetch", | ||
"build": "yarn clean && node ../../scripts/build.js", | ||
"postbuild": "tsc --emitDeclarationOnly --declaration --project tsconfig.json --outDir dist", | ||
"postbuild": "ttsc --project tsconfig.json --outDir dist", | ||
"lint": "eslint . --ext .js,.jsx,.tsx,.ts --fix", | ||
"format": "prettier --write .", | ||
"precommit": "yarn lint-staged" | ||
"precommit": "yarn lint-staged", | ||
"semantic-release": "semantic-release --ci" | ||
}, | ||
@@ -26,0 +27,0 @@ "peerDependencies": { |
# React Hyper Fetch | ||
[![BetterTyped](https://badgen.net/badge/icon/Created%20by%20BetterTyped?label&color=black&labelColor=black)](https://bettertyped.com) | ||
[![BetterTyped](https://img.shields.io/static/v1?label=Created%20by&message=BetterTyped&color=blue&logo=BT)](https://github.com/BetterTyped) | ||
[![Downloads](https://img.shields.io/npm/dm/@better-typed/react-hyper-fetch)](https://www.npmjs.com/package/@better-typed/react-hyper-fetch) | ||
@@ -15,38 +15,37 @@ [![NPM](https://img.shields.io/npm/v/@better-typed/react-hyper-fetch.svg)](https://www.npmjs.com/package/@better-typed/react-hyper-fetch) | ||
**`React Hyper Fetch`** is a set of tools and hooks for Hyper Fetch, that combined with React's lifecycle allow to | ||
create modern, optimized, maintainable and high quality solutions. | ||
create modern, optimized, maintainable and high quality solutions. We offer many hooks for your use, thanks to which you | ||
can download or mutate data, observe sent requests and interact with data in the cache. | ||
## Features | ||
🚀 Simple usage and powerful features | ||
##### 🚀 Simple usage and powerful features for rapid development | ||
🏭 Cache, request deduplication and auto refetching | ||
##### 🏆 Provide the best quality with a friendly working environment | ||
💎 Persistance and offline first support | ||
##### 🏭 Built-in support for query params and url parameters handling | ||
🎁 Queueing and auto refetching | ||
##### 💎 Cache and requests persistance options with rich offline first support | ||
🔧 Customizable and fully integrated with Hyper Fetch | ||
##### 🎁 Request queueing, deduplication, cancellation and retries | ||
👑 Window events and request cancellation | ||
##### 🔧 Easy access to internal logic for custom integrations and solutions | ||
##### 👑 Track full request lifecycle with ease | ||
##### 📡 Download/Upload progress with ETA and details | ||
##### 🔋 Accelerate your testing with shared commands setup | ||
##### 💡 Written with typescript in mind to create a safe environment | ||
## Sources | ||
- #### [Docs](https://hyperfetch.bettertyped.com/) | ||
- #### [Installation](https://hyperfetch.bettertyped.com/docs/Getting%20Started/Installation) | ||
- #### [Docs](https://hyperfetch.bettertyped.com/docs/React/Overview) | ||
- #### [API](https://hyperfetch.bettertyped.com/api/) | ||
- #### [NPM](https://www.npmjs.com/package/@better-typed/hyper-fetch) | ||
- #### [Guides](https://hyperfetch.bettertyped.com/guides/Basic/Dispatching) | ||
## Packages | ||
## Other Packages | ||
- #### [Hyper Fetch](https://github.com/BetterTyped/hyper-fetch/tree/main/packages/core) | ||
## Installation | ||
```bash | ||
npm install --save @better-typed/hyper-fetch @better-typed/react-hyper-fetch | ||
or | ||
yarn add @better-typed/hyper-fetch @better-typed/react-hyper-fetch | ||
``` | ||
## Checkout our page! | ||
### [Better Typed](https://bettertyped.com/docs/Overview) |
export * from "./use-command-events"; | ||
export * from "./use-debounce"; | ||
export * from "./use-dependent-state"; | ||
export * from "./use-tracked-state"; |
import { useRef } from "react"; | ||
import { | ||
ExtractError, | ||
isFailedRequest, | ||
ExtractResponse, | ||
@@ -14,3 +13,3 @@ CommandInstance, | ||
} from "@better-typed/hyper-fetch"; | ||
import { useDidUpdate, useIsMounted, useWillUnmount } from "@better-typed/react-lifecycle-hooks"; | ||
import { useIsMounted, useWillUnmount } from "@better-typed/react-lifecycle-hooks"; | ||
@@ -39,9 +38,6 @@ import { | ||
logger, | ||
state, | ||
actions, | ||
setCacheData, | ||
initializeCallbacks = false, | ||
}: UseCommandEventsOptionsType<T>): UseCommandEventsReturnType<T> => { | ||
const { cache, appManager, commandManager } = command.builder; | ||
const commandDump = command.dump(); | ||
const { cache, commandManager } = command.builder; | ||
@@ -115,17 +111,2 @@ const isMounted = useIsMounted(); | ||
const handleInitialCallbacks = () => { | ||
const hasData = state.data && state.error && state.timestamp; | ||
if (hasData && initializeCallbacks) { | ||
const details = { | ||
retries: state.retries, | ||
timestamp: new Date(state.timestamp as Date), | ||
isFailed: isFailedRequest([state.data, state.error, state.status]), | ||
isCanceled: false, | ||
isOffline: !appManager.isOnline, | ||
}; | ||
handleResponseCallbacks(command, [state.data, state.error, state.status], details); | ||
} | ||
}; | ||
// ****************** | ||
@@ -144,8 +125,8 @@ // Lifecycle | ||
const handleDownloadProgress = (progress: FetchProgressType) => { | ||
onDownloadProgressCallback?.current?.(progress); | ||
const handleDownloadProgress = (progress: FetchProgressType, details: CommandEventDetails<T>) => { | ||
onDownloadProgressCallback?.current?.(progress, details); | ||
}; | ||
const handleUploadProgress = (progress: FetchProgressType) => { | ||
onUploadProgressCallback?.current?.(progress); | ||
const handleUploadProgress = (progress: FetchProgressType, details: CommandEventDetails<T>) => { | ||
onUploadProgressCallback?.current?.(progress, details); | ||
}; | ||
@@ -170,3 +151,3 @@ | ||
const handleRemove = (requestId: string) => { | ||
const handleRemove = ({ requestId }: CommandEventDetails<T>) => { | ||
removeLifecycleListener(requestId); | ||
@@ -184,3 +165,3 @@ }; | ||
retries: 0, | ||
timestamp: new Date(), | ||
timestamp: +new Date(), | ||
isFailed: false, | ||
@@ -203,6 +184,6 @@ isCanceled: true, | ||
const addDataListener = (cmd: CommandInstance) => { | ||
const addDataListener = (cmd: T) => { | ||
// Data handlers | ||
const loadingUnmount = commandManager.events.onLoading(cmd.queueKey, handleGetLoadingEvent(cmd.queueKey)); | ||
const getResponseUnmount = cache.events.get<ExtractResponse<T>, ExtractError<T>>(cmd.cacheKey, setCacheData); | ||
const getResponseUnmount = cache.events.onData<ExtractResponse<T>, ExtractError<T>>(cmd.cacheKey, setCacheData); | ||
const abortUnmount = commandManager.events.onAbort(cmd.abortKey, handleAbort(cmd)); | ||
@@ -226,3 +207,3 @@ | ||
const addLifecycleListeners = (cmd: CommandInstance, requestId?: string) => { | ||
const addLifecycleListeners = (cmd: T, requestId?: string) => { | ||
if (!requestId) { | ||
@@ -288,7 +269,2 @@ const { queueKey, cacheKey } = cmd; | ||
/** | ||
* On the init if we have data we should call the callback functions | ||
*/ | ||
useDidUpdate(handleInitialCallbacks, [commandDump.cacheKey, commandDump.queueKey], true); | ||
/** | ||
* On unmount we want to clear all the listeners to prevent memory leaks | ||
@@ -295,0 +271,0 @@ */ |
@@ -6,5 +6,5 @@ import { | ||
ExtractResponse, | ||
LoggerMethodsType, | ||
LoggerType, | ||
FetchProgressType, | ||
ExtractFetchReturn, | ||
ExtractClientReturnType, | ||
CommandEventDetails, | ||
@@ -15,3 +15,3 @@ CommandInstance, | ||
import { UseDependentStateType, UseDependentStateActions } from "helpers"; | ||
import { UseTrackedStateActions } from "helpers"; | ||
@@ -26,24 +26,54 @@ // Misc | ||
dispatcher: Dispatcher; | ||
logger: LoggerMethodsType; | ||
state: UseDependentStateType<T>; | ||
actions: UseDependentStateActions<T>; | ||
logger: LoggerType; | ||
actions: UseTrackedStateActions<T>; | ||
setCacheData: (cacheData: CacheValueType<ExtractResponse<T>, ExtractError<T>>) => void; | ||
initializeCallbacks?: boolean; | ||
}; | ||
export type UseCommandEventsActionsType<T extends CommandInstance> = { | ||
/** | ||
* Callback which allows to cancel ongoing requests from given queueKey. | ||
*/ | ||
abort: () => void; | ||
/** | ||
* Helper hook listening on success response. | ||
*/ | ||
onSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on error response. | ||
*/ | ||
onError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on aborting of requests. Abort events are not triggering onError callbacks. | ||
*/ | ||
onAbort: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on request going into offline awaiting for network connection to be restored. It will not trigger onError when 'offline' mode is set on command. | ||
*/ | ||
onOfflineError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on any response. | ||
*/ | ||
onFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on request start. | ||
*/ | ||
onRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on response start(before we receive all data from server). | ||
*/ | ||
onResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on download progress ETA. We can later match given requests by their id's or command instance which holds all data which is being transferred. | ||
*/ | ||
onDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
/** | ||
* Helper hook listening on upload progress ETA. We can later match given requests by their id's or command instance which holds all data which is being transferred. | ||
*/ | ||
onUploadProgress: (callback: OnProgressCallbackType) => void; | ||
}; | ||
// Return | ||
export type UseCommandEventsReturnType<T extends CommandInstance> = [ | ||
UseCommandEventsActionsType<T>, | ||
{ | ||
abort: () => void; | ||
onSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
onError: (callback: OnErrorCallbackType<T>) => void; | ||
onAbort: (callback: OnErrorCallbackType<T>) => void; | ||
onOfflineError: (callback: OnErrorCallbackType<T>) => void; | ||
onFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
onRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
onResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
onDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
onUploadProgress: (callback: OnProgressCallbackType) => void; | ||
}, | ||
{ | ||
addDataListener: (command: CommandInstance) => VoidFunction; | ||
@@ -72,3 +102,3 @@ clearDataListener: VoidFunction; | ||
export type OnFinishedCallbackType<Command extends CommandInstance> = ( | ||
params: CallbackParameters<Command, ExtractFetchReturn<Command>>, | ||
params: CallbackParameters<Command, ExtractClientReturnType<Command>>, | ||
) => void; | ||
@@ -79,2 +109,5 @@ export type OnStartCallbackType<Command extends CommandInstance> = (params: { | ||
}) => void; | ||
export type OnProgressCallbackType = (progress: FetchProgressType) => void; | ||
export type OnProgressCallbackType = <Command extends CommandInstance>( | ||
progress: FetchProgressType, | ||
details: CommandEventDetails<Command>, | ||
) => void; |
@@ -5,3 +5,5 @@ import { useState } from "react"; | ||
export const useAppManager = <B extends BuilderInstance>(builder: B) => { | ||
import { UseAppManagerReturnType } from "use-app-manager"; | ||
export const useAppManager = <B extends BuilderInstance>(builder: B): UseAppManagerReturnType => { | ||
const [online, setIsOnline] = useState(builder.appManager.isOnline); | ||
@@ -8,0 +10,0 @@ const [focused, setIsFocused] = useState(builder.appManager.isFocused); |
export type UseAppManagerReturnType = { | ||
/** | ||
* Is window focused | ||
*/ | ||
isFocused: boolean; | ||
/** | ||
* Network online status | ||
*/ | ||
isOnline: boolean; | ||
/** | ||
* Network state setter | ||
*/ | ||
setOnline: (isOnline: boolean) => void; | ||
/** | ||
* Focus state setter | ||
*/ | ||
setFocused: (isFocused: boolean) => void; | ||
}; |
import { useRef } from "react"; | ||
import { getCommandDispatcher, CommandInstance, Command, getCommandKey } from "@better-typed/hyper-fetch"; | ||
import { useCommandEvents, useDependentState } from "helpers"; | ||
import { UseCacheOptionsType, useCacheDefaultOptions } from "use-cache"; | ||
import { useCommandEvents, UseTrackedState } from "helpers"; | ||
import { UseCacheOptionsType, useCacheDefaultOptions, UseCacheReturnType } from "use-cache"; | ||
@@ -14,3 +14,3 @@ export const useCache = <T extends CommandInstance>( | ||
}: UseCacheOptionsType<T> = useCacheDefaultOptions, | ||
) => { | ||
): UseCacheReturnType<T> => { | ||
const { cacheKey, builder } = command; | ||
@@ -26,3 +26,3 @@ | ||
*/ | ||
const [state, actions, { setRenderKey, setCacheData }] = useDependentState<T>({ | ||
const [state, actions, { setRenderKey, setCacheData }] = UseTrackedState<T>({ | ||
logger, | ||
@@ -40,3 +40,2 @@ command, | ||
const [callbacks] = useCommandEvents({ | ||
state, | ||
logger, | ||
@@ -49,9 +48,9 @@ actions, | ||
const revalidate = (revalidateKey?: string | CommandInstance | RegExp) => { | ||
if (revalidateKey && revalidateKey instanceof Command) { | ||
cache.events.revalidate(`/${getCommandKey(revalidateKey, true)}/`); | ||
} else if (revalidateKey) { | ||
cache.events.revalidate(revalidateKey); | ||
const revalidate = (invalidateKey?: string | CommandInstance | RegExp) => { | ||
if (invalidateKey && invalidateKey instanceof Command) { | ||
cache.revalidate(`/${getCommandKey(invalidateKey, true)}/`); | ||
} else if (invalidateKey && !(invalidateKey instanceof Command)) { | ||
cache.revalidate(invalidateKey); | ||
} else { | ||
cache.events.revalidate(cacheKey); | ||
cache.revalidate(cacheKey); | ||
} | ||
@@ -58,0 +57,0 @@ }; |
@@ -8,20 +8,39 @@ import { CommandInstance, ExtractResponse, ExtractError, CacheValueType } from "@better-typed/hyper-fetch"; | ||
OnSuccessCallbackType, | ||
UseDependentStateActions, | ||
UseDependentStateType, | ||
UseTrackedStateActions, | ||
UseTrackedStateType, | ||
} from "helpers"; | ||
export type UseCacheOptionsType<T extends CommandInstance> = { | ||
/** | ||
* If `true` it will rerender only when values used by our component gets changed. Otherwise it will rerender on any change. | ||
*/ | ||
dependencyTracking?: boolean; | ||
/** | ||
* If cache is empty we can use placeholder data. | ||
*/ | ||
initialData?: CacheValueType<ExtractResponse<T>, ExtractError<T>>["data"] | null; | ||
/** | ||
* Deep comparison function for hook to check for equality in incoming data, to limit rerenders. | ||
*/ | ||
deepCompare?: boolean | typeof isEqual; | ||
}; | ||
export type UseCacheReturnType<T extends CommandInstance> = UseDependentStateType<T> & { | ||
actions: UseDependentStateActions<T>; | ||
onCacheSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
onCacheError: (callback: OnErrorCallbackType<T>) => void; | ||
onCacheChange: (callback: OnFinishedCallbackType<T>) => void; | ||
isStale: boolean; | ||
isRefreshingError: boolean; | ||
revalidate: (revalidateKey?: string | CommandInstance) => void; | ||
}; | ||
export type UseCacheReturnType<T extends CommandInstance> = UseTrackedStateType<T> & | ||
UseTrackedStateActions<T> & { | ||
/** | ||
* Helper hook listener for success response | ||
*/ | ||
onCacheSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
/** | ||
* Helper hook listener for error response | ||
*/ | ||
onCacheError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listener for response | ||
*/ | ||
onCacheChange: (callback: OnFinishedCallbackType<T>) => void; | ||
/** | ||
* Revalidate current command resource or pass custom key to trigger it by invalidationKey(Regex / cacheKey). | ||
*/ | ||
revalidate: (invalidateKey?: string | CommandInstance) => void; | ||
}; |
@@ -5,4 +5,4 @@ import { useRef } from "react"; | ||
import { useDebounce, useCommandEvents, useDependentState } from "helpers"; | ||
import { UseFetchOptionsType, useFetchDefaultOptions } from "use-fetch"; | ||
import { useDebounce, useCommandEvents, UseTrackedState } from "helpers"; | ||
import { UseFetchOptionsType, useFetchDefaultOptions, UseFetchReturnType } from "use-fetch"; | ||
@@ -33,3 +33,3 @@ /** | ||
}: UseFetchOptionsType<T> = useFetchDefaultOptions, | ||
) => { | ||
): UseFetchReturnType<T> => { | ||
const updateKey = JSON.stringify(command.dump()); | ||
@@ -47,3 +47,3 @@ const requestDebounce = useDebounce(debounceTime); | ||
*/ | ||
const [state, actions, { setRenderKey, setCacheData, getStaleStatus }] = useDependentState<T>({ | ||
const [state, actions, { setRenderKey, setCacheData, getStaleStatus }] = UseTrackedState<T>({ | ||
logger, | ||
@@ -61,3 +61,2 @@ command, | ||
const [callbacks, listeners] = useCommandEvents({ | ||
state, | ||
logger, | ||
@@ -77,3 +76,3 @@ actions, | ||
if (!disabled) { | ||
logger.debug(`Adding request to fetch queue`); | ||
logger.debug(`Fetching data`); | ||
dispatcher.add(command); | ||
@@ -115,5 +114,5 @@ } else { | ||
if (invalidateKey && invalidateKey instanceof Command) { | ||
cache.events.revalidate(getCommandKey(invalidateKey)); | ||
} else if (invalidateKey) { | ||
cache.events.revalidate(invalidateKey); | ||
cache.revalidate(getCommandKey(invalidateKey)); | ||
} else if (invalidateKey && !(invalidateKey instanceof Command)) { | ||
cache.revalidate(invalidateKey); | ||
} else { | ||
@@ -131,3 +130,4 @@ handleFetch(); | ||
const hasStaleData = getStaleStatus(); | ||
if (revalidateOnMount || hasStaleData) { | ||
const isFetching = dispatcher.getIsActiveQueue(queueKey); | ||
if (revalidateOnMount || (hasStaleData && !isFetching)) { | ||
handleFetch(); | ||
@@ -134,0 +134,0 @@ } |
import { CommandInstance, ExtractResponse, ExtractError, CacheValueType } from "@better-typed/hyper-fetch"; | ||
import { | ||
OnErrorCallbackType, | ||
OnFinishedCallbackType, | ||
OnProgressCallbackType, | ||
OnStartCallbackType, | ||
OnSuccessCallbackType, | ||
UseDependentStateActions, | ||
UseDependentStateType, | ||
} from "helpers"; | ||
import { UseCommandEventsActionsType, UseTrackedStateActions, UseTrackedStateType } from "helpers"; | ||
import { isEqual } from "utils"; | ||
export type UseFetchOptionsType<T extends CommandInstance> = { | ||
/** | ||
* Refetch dependencies | ||
*/ | ||
dependencies?: any[]; | ||
/** | ||
* Disable fetching | ||
*/ | ||
disabled?: boolean; | ||
/** | ||
* If `true` it will rerender only when values used by our component gets changed. Otherwise it will rerender on any change. | ||
*/ | ||
dependencyTracking?: boolean; | ||
/** | ||
* If `true` it will refetch data in background no matter if we have it from cache. | ||
*/ | ||
revalidateOnMount?: boolean; | ||
/** | ||
* If cache is empty we can use placeholder data. | ||
*/ | ||
initialData?: CacheValueType<ExtractResponse<T>, ExtractError<T>>["data"] | null; | ||
/** | ||
* Enable/disable refresh data | ||
*/ | ||
refresh?: boolean; | ||
/** | ||
* Refresh data interval time | ||
*/ | ||
refreshTime?: number; | ||
/** | ||
* Enable/disable data refresh if our tab is not focused(used by user at given time). | ||
*/ | ||
refreshBlurred?: boolean; | ||
/** | ||
* Enable/disable data refresh if user leaves current tab. | ||
*/ | ||
refreshOnTabBlur?: boolean; | ||
/** | ||
* Enable/disable data refresh if user enters current tab. | ||
*/ | ||
refreshOnTabFocus?: boolean; | ||
/** | ||
* Enable/disable data refresh if network is restored. | ||
*/ | ||
refreshOnReconnect?: boolean; | ||
/** | ||
* Enable/disable debouncing for often changing keys or refreshing, to limit requests to server. | ||
*/ | ||
debounce?: boolean; | ||
/** | ||
* How long it should debounce requests. | ||
*/ | ||
debounceTime?: number; | ||
/** | ||
* Deep comparison function for hook to check for equality in incoming data, to limit rerenders. | ||
*/ | ||
deepCompare?: boolean | typeof isEqual; | ||
}; | ||
export type UseFetchReturnType<T extends CommandInstance> = UseDependentStateType<T> & { | ||
actions: UseDependentStateActions<T>; | ||
onSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
onError: (callback: OnErrorCallbackType<T>) => void; | ||
onFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
onRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
onResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
onDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
onUploadProgress: (callback: OnProgressCallbackType) => void; | ||
isRefreshed: boolean; | ||
isRefreshingError: boolean; | ||
isDebouncing: boolean; | ||
isStale: boolean; | ||
revalidate: (invalidateKey?: string | CommandInstance) => void; | ||
abort: VoidFunction; | ||
}; | ||
export type UseFetchReturnType<T extends CommandInstance> = UseTrackedStateType<T> & | ||
UseTrackedStateActions<T> & | ||
UseCommandEventsActionsType<T> & { | ||
/** | ||
* Is debounce active at given moment | ||
*/ | ||
isDebouncing: boolean; | ||
/** | ||
* Revalidate current command resource or pass custom key to trigger it by invalidationKey(Regex / cacheKey). | ||
*/ | ||
revalidate: (invalidateKey?: string | CommandInstance) => void; | ||
}; |
import { RequiredKeys } from "@better-typed/hyper-fetch"; | ||
import { UseQueueOptions } from "use-queue"; | ||
import { UseQueueOptionsType } from "use-queue"; | ||
export const useQueueDefaultOptions: RequiredKeys<UseQueueOptions> = { | ||
export const useQueueDefaultOptions: RequiredKeys<UseQueueOptionsType> = { | ||
queueType: "auto", | ||
}; |
@@ -5,3 +5,3 @@ import { useState, useRef } from "react"; | ||
import { UseQueueOptions, useQueueDefaultOptions, QueueRequest } from "use-queue"; | ||
import { UseQueueOptionsType, useQueueDefaultOptions, QueueRequest, UseQueueReturnType } from "use-queue"; | ||
@@ -16,4 +16,4 @@ /** | ||
command: Command, | ||
options: UseQueueOptions = useQueueDefaultOptions, | ||
) => { | ||
options: UseQueueOptionsType = useQueueDefaultOptions, | ||
): UseQueueReturnType<Command> => { | ||
const { queueType = useQueueDefaultOptions.queueType } = options; | ||
@@ -23,3 +23,3 @@ const { abortKey, queueKey, builder } = command; | ||
const dispatcher = getCommandDispatcher(command, queueType); | ||
const [dispatcher] = getCommandDispatcher(command, queueType); | ||
@@ -49,4 +49,3 @@ const unmountCallbacks = useRef<null | VoidFunction>(null); | ||
const getInitialState = () => { | ||
const [queue] = dispatcher; | ||
const commandQueue = queue.getQueue<Command>(queueKey); | ||
const commandQueue = dispatcher.getQueue<Command>(queueKey); | ||
@@ -57,2 +56,7 @@ setStopped(commandQueue.stopped); | ||
const updateQueueState = (values: { requests: QueueRequest<Command>[]; stopped: boolean }) => { | ||
setStopped(values.stopped); | ||
setRequests(createRequestsArray(values.requests)); | ||
}; | ||
// ****************** | ||
@@ -63,7 +67,4 @@ // Events | ||
const mountEvents = () => { | ||
const [queue] = dispatcher; | ||
const unmountChange = queue.events.onQueueChange<Command>(queueKey, (values) => { | ||
setStopped(values.stopped); | ||
setRequests(createRequestsArray(values.requests)); | ||
}); | ||
const unmountChange = dispatcher.events.onQueueChange<Command>(queueKey, updateQueueState); | ||
const unmountStatus = dispatcher.events.onQueueStatus<Command>(queueKey, updateQueueState); | ||
@@ -74,11 +75,6 @@ const unmountDownload = commandManager.events.onDownloadProgress(queueKey, (progress, { requestId }) => { | ||
const unmountUpload = commandManager.events.onDownloadProgress(queueKey, (progress, { requestId }) => { | ||
const unmountUpload = commandManager.events.onUploadProgress(queueKey, (progress, { requestId }) => { | ||
setRequests((prev) => prev.map((el) => (el.requestId === requestId ? { ...el, uploading: progress } : el))); | ||
}); | ||
const unmountStatus = queue.events.onQueueStatus<Command>(queueKey, (values) => { | ||
setStopped(values.stopped); | ||
setRequests(createRequestsArray(values.requests)); | ||
}); | ||
const unmount = () => { | ||
@@ -93,3 +89,2 @@ unmountStatus(); | ||
unmountCallbacks.current = unmount; | ||
return unmount; | ||
@@ -96,0 +91,0 @@ }; |
import { FetchProgressType, CommandInstance, DispatcherDumpValueType } from "@better-typed/hyper-fetch"; | ||
export type UseQueueOptions = { | ||
export type UseQueueOptionsType = { | ||
queueType?: "auto" | "fetch" | "submit"; | ||
@@ -8,6 +8,21 @@ }; | ||
export type QueueRequest<Command extends CommandInstance> = DispatcherDumpValueType<Command> & { | ||
/** | ||
* Uploading progress for given request | ||
*/ | ||
uploading?: FetchProgressType; | ||
/** | ||
* Downloading progress for given request | ||
*/ | ||
downloading?: FetchProgressType; | ||
/** | ||
* Callback which allow to start previously stopped request. | ||
*/ | ||
startRequest: () => void; | ||
/** | ||
* Callback which allow to stop request and cancel it if it's ongoing. | ||
*/ | ||
stopRequest: () => void; | ||
/** | ||
* Removes request from the queue | ||
*/ | ||
deleteRequest: () => void; | ||
@@ -17,7 +32,22 @@ }; | ||
export type UseQueueReturnType<T extends CommandInstance> = { | ||
/** | ||
* Queue status for provided command | ||
*/ | ||
stopped: boolean; | ||
/** | ||
* List of requests for provided command | ||
*/ | ||
requests: QueueRequest<T>[]; | ||
/** | ||
* Callback which allow to stop queue, it will cancel ongoing requests. | ||
*/ | ||
stop: () => void; | ||
/** | ||
* Callback which allow to pause queue. It will allow ongoing requests to be finished, but will stop next from being send. | ||
*/ | ||
pause: () => void; | ||
/** | ||
* Callback which allow to start queue. | ||
*/ | ||
start: () => void; | ||
}; |
@@ -5,11 +5,11 @@ import { useRef } from "react"; | ||
getCommandKey, | ||
ExtractFetchReturn, | ||
ExtractClientReturnType, | ||
commandSendRequest, | ||
CommandInstance, | ||
} from "@better-typed/hyper-fetch"; | ||
import { useDebounce, useDependentState, useCommandEvents } from "helpers"; | ||
import { UseSubmitOptionsType, useSubmitDefaultOptions } from "use-submit"; | ||
import { useDidMount } from "@better-typed/react-lifecycle-hooks"; | ||
import { useDebounce, UseTrackedState, useCommandEvents } from "helpers"; | ||
import { UseSubmitOptionsType, useSubmitDefaultOptions, UseSubmitReturnType } from "use-submit"; | ||
/** | ||
@@ -31,3 +31,3 @@ * This hooks aims to mutate data on the server. | ||
}: UseSubmitOptionsType<T> = useSubmitDefaultOptions, | ||
) => { | ||
): UseSubmitReturnType<T> => { | ||
/** | ||
@@ -46,3 +46,3 @@ * Because of the dynamic cacheKey / queueKey signing within the command we need to store it's latest instance | ||
*/ | ||
const [state, actions, { setRenderKey, setCacheData }] = useDependentState<T>({ | ||
const [state, actions, { setRenderKey, setCacheData }] = UseTrackedState<T>({ | ||
logger, | ||
@@ -60,3 +60,2 @@ command, | ||
const [callbacks, listeners] = useCommandEvents({ | ||
state, | ||
logger, | ||
@@ -80,3 +79,3 @@ actions, | ||
if (disabled) { | ||
logger.debug(`Cannot add to submit queue`, { disabled, options }); | ||
logger.warning(`Cannot submit request`, { disabled, options }); | ||
return [null, null, 0]; | ||
@@ -92,5 +91,5 @@ } | ||
return new Promise<ExtractFetchReturn<T> | [null, null, null]>((resolve) => { | ||
return new Promise<ExtractClientReturnType<T> | [null, null, null]>((resolve) => { | ||
const performSubmit = async () => { | ||
logger.debug(`Adding request to submit queue`, { disabled, options }); | ||
logger.debug(`Submitting request`, { disabled, options }); | ||
@@ -120,5 +119,5 @@ if (debounce) { | ||
if (invalidateKey && invalidateKey instanceof Command) { | ||
cache.events.revalidate(getCommandKey(invalidateKey)); | ||
} else { | ||
cache.events.revalidate(invalidateKey); | ||
cache.revalidate(getCommandKey(invalidateKey)); | ||
} else if (!(invalidateKey instanceof Command)) { | ||
cache.revalidate(invalidateKey); | ||
} | ||
@@ -180,6 +179,5 @@ }; | ||
...handlers, | ||
isDebouncing: false, | ||
isRefreshed: false, | ||
isDebouncing: requestDebounce.active, | ||
revalidate, | ||
}; | ||
}; |
@@ -10,34 +10,91 @@ import { CacheValueType, ExtractError, ExtractResponse, CommandInstance } from "@better-typed/hyper-fetch"; | ||
OnSuccessCallbackType, | ||
UseDependentStateType, | ||
UseDependentStateActions, | ||
UseTrackedStateType, | ||
UseTrackedStateActions, | ||
} from "helpers"; | ||
export type UseSubmitOptionsType<T extends CommandInstance> = { | ||
/** | ||
* Disable fetching | ||
*/ | ||
disabled?: boolean; | ||
invalidate?: (string | CommandInstance)[]; | ||
cacheOnMount?: boolean; | ||
/** | ||
* If cache is empty we can use placeholder data. | ||
*/ | ||
initialData?: CacheValueType<ExtractResponse<T>, ExtractError<T>>["data"] | null; | ||
/** | ||
* Enable/disable debouncing for often changing keys or refreshing, to limit requests to server. | ||
*/ | ||
debounce?: boolean; | ||
/** | ||
* How long it should debounce requests. | ||
*/ | ||
debounceTime?: number; | ||
suspense?: boolean; | ||
shouldThrow?: boolean; | ||
/** | ||
* If `true` it will rerender only when values used by our component gets changed. Otherwise it will rerender on any change. | ||
*/ | ||
dependencyTracking?: boolean; | ||
/** | ||
* Deep comparison function for hook to check for equality in incoming data, to limit rerenders. | ||
*/ | ||
deepCompare?: boolean | typeof isEqual; | ||
}; | ||
export type UseSubmitReturnType<T extends CommandInstance> = Omit<UseDependentStateType<T>, "loading"> & { | ||
actions: UseDependentStateActions<T>; | ||
onSubmitSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
onSubmitError: (callback: OnErrorCallbackType<T>) => void; | ||
onSubmitFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
onSubmitRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
onSubmitResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
onSubmitDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
onSubmitUploadProgress: (callback: OnProgressCallbackType) => void; | ||
submit: (...parameters: Parameters<T["send"]>) => void; | ||
submitting: boolean; | ||
abort: VoidFunction; | ||
isStale: boolean; | ||
isDebouncing: boolean; | ||
revalidate: (revalidateKey: string | CommandInstance | RegExp) => void; | ||
}; | ||
export type UseSubmitReturnType<T extends CommandInstance> = Omit<UseTrackedStateType<T>, "loading"> & | ||
UseTrackedStateActions<T> & { | ||
/** | ||
* Callback which allows to cancel ongoing requests from given queueKey. | ||
*/ | ||
abort: () => void; | ||
/** | ||
* Helper hook listening on success response. | ||
*/ | ||
onSubmitSuccess: (callback: OnSuccessCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on error response. | ||
*/ | ||
onSubmitError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on any response. | ||
*/ | ||
onSubmitFinished: (callback: OnFinishedCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on request start. | ||
*/ | ||
onSubmitRequestStart: (callback: OnStartCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on response start(before we receive all data from server). | ||
*/ | ||
onSubmitResponseStart: (callback: OnStartCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on download progress ETA. We can later match given requests by their id's or command instance which holds all data which is being transferred. | ||
*/ | ||
onSubmitDownloadProgress: (callback: OnProgressCallbackType) => void; | ||
/** | ||
* Helper hook listening on upload progress ETA. We can later match given requests by their id's or command instance which holds all data which is being transferred. | ||
*/ | ||
onSubmitUploadProgress: (callback: OnProgressCallbackType) => void; | ||
/** | ||
* Helper hook listening on aborting of requests. Abort events are not triggering onError callbacks. | ||
*/ | ||
onSubmitAbort: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Helper hook listening on request going into offline awaiting for network connection to be restored. It will not trigger onError when 'offline' mode is set on command. | ||
*/ | ||
onSubmitOfflineError: (callback: OnErrorCallbackType<T>) => void; | ||
/** | ||
* Method responsible for triggering requests. It return Promise which will be resolved with the request. | ||
*/ | ||
submit: (...parameters: Parameters<T["send"]>) => void; | ||
/** | ||
* Request loading state | ||
*/ | ||
submitting: boolean; | ||
/** | ||
* Is debounce active at given moment | ||
*/ | ||
isDebouncing: boolean; | ||
/** | ||
* Revalidate current command resource or pass custom key to trigger it by invalidationKey(Regex / cacheKey). | ||
*/ | ||
revalidate: (invalidateKey: string | CommandInstance | RegExp) => void; | ||
}; |
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
988899
166
0
6561
2
51