Skip to main content
Version: v8.0.0

Managers

Managers are core subsystems in Hyper Fetch that handle essential app-wide concerns—like network status, request lifecycle, and logging. They provide powerful, centralized APIs for managing state, events, and behaviors across your application, making advanced features like offline support, cancellation, and debugging easy to implement and maintain in other environments like React, Node.js, etc.

The library contains several managers, each supporting a specific subsystem or feature. Understanding these managers helps you unlock advanced capabilities and build robust, maintainable applications.


AppManager

Read the API Reference »

The AppManager detects and manages your application's online/offline state, tracks window focus and blur events, and allows integration with custom event sources (such as React Native or Electron). It provides unmount callbacks for easy cleanup, making it simple to handle app-wide lifecycle events in any environment.

Purpose
  1. Track online/offline status of the app
  2. Detect window focus and blur events
  3. Allow custom event sources for different environments
Listening to App Events
const unmountFocusListener = client.appManager.events.onFocus(() => {
console.log("App is focused!");
});
const unmountOfflineListener = client.appManager.events.onOffline(() => {
console.log("App is offline!");
});

// ... later, to clean up:
unmountFocusListener();
unmountOfflineListener();
info

Hyper Fetch event listeners always return unmounting callbacks for easier cleanup handling.

Customizing Events

If you're using a non-browser environment (like React Native), you can set custom event handlers:

client.appManager.setFocusEvents({
onFocus: myCustomFocusHandler,
onBlur: myCustomBlurHandler,
});

Events

getAppManagerEvents
Name Type Description
emitBlur
() => void
Emit when the application window loses focus
emitFocus
() => void
Emit when the application window gains focus
emitOffline
() => void
Emit when the application transitions to offline state
emitOnline
() => void
Emit when the application transitions to online state
onBlur
(callback: () => void) => VoidFunction
Listen for blur events
onFocus
(callback: () => void) => VoidFunction
Listen for focus events
onOffline
(callback: () => void) => VoidFunction
Listen for offline state transitions
onOnline
(callback: () => void) => VoidFunction
Listen for online state transitions


RequestManager

Read the API Reference »

The RequestManager manages cancellation tokens for requests, emits events throughout the request lifecycle (including start, upload, download, response, and abort), and supports aborting requests by requestId or custom abortKey. It enables granular progress tracking and advanced cancellation scenarios for robust request handling.

Purpose
  1. Manage cancellation tokens for requests
  2. Emit events for request lifecycle (start, upload, download, response, abort)
  3. Support aborting by requestId or abortKey

Bulk Abort

The abortAll() method aborts every in-flight request tracked by the RequestManager. This is useful for cleanup on unmount, page navigation, or test teardown.

// Abort all tracked requests at once
client.requestManager.abortAll();
Tracking Upload/Download Progress
const unmountUploadListener = client.requestManager.events.onUploadProgressById(requestId, (progress) => {
console.log("Upload progress:", progress);
});
const unmountDownloadListener = client.requestManager.events.onDownloadProgressById(requestId, (progress) => {
console.log("Download progress:", progress);
});

// ... later, to clean up:
unmountUploadListener();
unmountDownloadListener();
info

You can abort requests by their requestId or by a custom abortKey to cancel groups of requests at once.

AbortKey

Every request added to the dispatcher creates an abort controller, stored in a Map under its abort key (usually the requestId). This lets you abort single requests or groups of requests easily.

const getUser = client.createRequest()({
method: "GET",
endpoint: "/users/:userId",
});

const abortKey = getUser.abortKey; // "/users/:userId"
const abortKeyWithParams = getUser.setParams({ userId: 1 }).abortKey; // "/users/1"
const abortKeyWithQueryParams = getUser.setQueryParams({ page: 1 }).abortKey; // "/users/:userId"

Custom abortKey

You can also set a custom abort key:

import { client } from "./api";

const getUser = client.createRequest()({
method: "GET",
endpoint: "/users/:userId",
abortKey: "CUSTOM_ABORT_KEY",
});

console.log(getUser.abortKey); // "CUSTOM_ABORT_KEY"

Generic abortKey

You can also set a generic abort key:

import { client } from "./api";

client.setQueryKeyMapper((request) => {
if (request.requestOptions.endpoint === "/users/:userId") {
return `CUSTOM_ABORT_KEY_${request.params?.userId || "unknown"}`;
}
});

const getUser = client.createRequest()({
method: "GET",
endpoint: "/users/:userId",
});

console.log(getUser.setParams({ userId: 1 }).queryKey); // "CUSTOM_QUERY_KEY_1"

Events

getRequestManagerEvents
Name Type Description
emitAbort
(data: RequestEventType<RequestInstance>, isTriggeredExternally: boolean) => void
Emit when a request is aborted
emitDeduplicated
(data: RequestDeduplicatedEventType<RequestInstance>, isTriggeredExternally: boolean) => void
Emit when a request is deduplicated (skipped because an identical one is in-flight)
emitDownloadProgress
(data: RequestProgressEventType<RequestInstance>, isTriggeredExternally: boolean) => void
Emit download progress updates
emitLoading
(data: RequestLoadingEventType<RequestInstance>, isTriggeredExternally: boolean) => void
Emit loading state changes for a request
emitRemove
(data: RequestRemovedEventType<RequestInstance>, isTriggeredExternally: boolean) => void
Emit when a request is removed from the dispatcher queue
emitRequestStart
(data: RequestEventType<RequestInstance>, isTriggeredExternally: boolean) => void
Emit when a request starts being sent
emitResponse
<Adapter>(data: RequestResponseEventType<ExtendRequest<RequestInstance, { client: Client<any, Adapter> }>>, isTriggeredExternally: boolean) => void
Emit when a response is received
emitResponseStart
(data: RequestEventType<RequestInstance>, isTriggeredExternally: boolean) => void
Emit when the response starts being received
emitUploadProgress
(data: RequestProgressEventType<RequestInstance>, isTriggeredExternally: boolean) => void
Emit upload progress updates
onAbort
<T>(callback: (request: RequestEventType<T>) => void) => VoidFunction
onAbortById
<T>(requestId: string, callback: (data: RequestEventType<T>) => void) => VoidFunction
onAbortByKey
<T>(abortKey: string, callback: (request: RequestEventType<T>) => void) => VoidFunction
onDeduplicated
<T>(callback: (data: RequestDeduplicatedEventType<T>) => void) => VoidFunction
Listen for deduplicated request events
onDeduplicatedByCache
<T>(cacheKey: string, callback: (data: RequestDeduplicatedEventType<T>) => void) => VoidFunction
onDeduplicatedById
<T>(requestId: string, callback: (data: RequestDeduplicatedEventType<T>) => void) => VoidFunction
onDeduplicatedByQueue
<T>(queryKey: string, callback: (data: RequestDeduplicatedEventType<T>) => void) => VoidFunction
onDownloadProgress
<T>(callback: (data: RequestProgressEventType<T>) => void) => VoidFunction
onDownloadProgressById
<T>(requestId: string, callback: (data: RequestProgressEventType<T>) => void) => VoidFunction
onDownloadProgressByQueue
<T>(queryKey: string, callback: (data: RequestProgressEventType<T>) => void) => VoidFunction
onLoading
<T>(callback: (data: RequestLoadingEventType<T>) => void) => VoidFunction
onLoadingByCache
<T>(cacheKey: string, callback: (data: RequestLoadingEventType<T>) => void) => VoidFunction
onLoadingById
<T>(requestId: string, callback: (data: RequestLoadingEventType<T>) => void) => VoidFunction
onLoadingByQueue
<T>(queryKey: string, callback: (data: RequestLoadingEventType<T>) => void) => VoidFunction
onRemove
<T>(callback: (data: RequestRemovedEventType<T>) => void) => VoidFunction
onRemoveById
<T>(requestId: string, callback: (data: RequestRemovedEventType<T>) => void) => VoidFunction
onRemoveByQueue
<T>(queryKey: string, callback: (data: RequestRemovedEventType<T>) => void) => VoidFunction
onRequestStart
<T>(callback: (details: RequestEventType<T>) => void) => VoidFunction
onRequestStartById
<T>(requestId: string, callback: (details: RequestEventType<T>) => void) => VoidFunction
onRequestStartByQueue
<T>(queryKey: string, callback: (details: RequestEventType<T>) => void) => VoidFunction
onResponse
<T>(callback: (data: RequestResponseEventType<T>) => void) => VoidFunction
onResponseByCache
<T>(cacheKey: string, callback: (data: RequestResponseEventType<T>) => void) => VoidFunction
onResponseById
<T>(requestId: string, callback: (data: RequestResponseEventType<T>) => void) => VoidFunction
onResponseStart
<T>(callback: (details: RequestEventType<T>) => void) => VoidFunction
onResponseStartById
<T>(requestId: string, callback: (details: RequestEventType<T>) => void) => VoidFunction
onResponseStartByQueue
<T>(queryKey: string, callback: (details: RequestEventType<T>) => void) => VoidFunction
onUploadProgress
<T>(callback: (data: RequestProgressEventType<T>) => void) => VoidFunction
onUploadProgressById
<T>(requestId: string, callback: (data: RequestProgressEventType<T>) => void) => VoidFunction
onUploadProgressByQueue
<T>(queryKey: string, callback: (data: RequestProgressEventType<T>) => void) => VoidFunction

client.requestManager.events.onResponse((response, details) => {
// Handle response
});

LoggerManager

Read the API Reference »

The LoggerManager centralizes logging for all subsystems, enables creation of custom loggers for different modules or features, and ensures consistent logging by inheriting parent configuration. It offers flexible log levels and output formatting to keep logs organized and actionable.

Purpose
  1. Centralize logging for all subsystems
  2. Enable creation of custom loggers for modules/features
  3. Inherit parent configuration for consistent logging
Debug mode required

client.setDebug(true) must be called for any log output to appear. Without it, the LoggerManager silently discards all messages regardless of log level.

const client = createClient({ url: "http://localhost:3000" }).setDebug(true);
Custom Logger Example
const logger = client.loggerManager.init("My Module");
logger.error("Something went wrong!"); // Output: [My Module] Something went wrong!

Filtering Logs by Module

Use setModules to restrict log output to specific module names. When set, only loggers whose names match the provided list will produce output. Pass undefined to remove the filter and show all modules.

// Only show logs from "Cache" and "Dispatcher" modules
client.loggerManager.setModules(["Cache", "Dispatcher"]);

// Show all modules again
client.loggerManager.setModules(undefined);

Best Practices
  • Always clean up event listeners using the returned unmount callbacks to avoid memory leaks.
  • Use custom abort keys for advanced cancellation scenarios (e.g., aborting all requests for a specific feature).
  • Leverage custom loggers to keep logs organized and actionable.

See Also

Client
The central hub for configuration and manager access.
Request
Learn how requests interact with managers.
Advanced Cancellation
Guide to advanced request cancellation techniques.