HTTP client with interceptors, timeout, retry, cache, deduplication, and download progress.
-const api = new Request('https://api.example.com')
// Directly awaitable
const user = await api.get<User>('/users/1')
// Lifecycle callbacks
await api.get('/users', {
onSuccess: setUsers,
onError: toast.error,
onFinally: () => setLoading(false),
})
-
-Prefer small focused instances over one instance with all interceptors:
-// ── Building blocks (pure functions, reusable) ──
const addAuth: RequestInterceptor = (config) => ({
...config,
headers: { ...config.headers, Authorization: `Bearer ${getToken()}` }
})
const addLang: RequestInterceptor = (config) => ({
...config,
headers: { ...config.headers, 'Accept-Language': 'zh-CN' }
})
// ── Compose: each instance handles one concern ──
const authApi = new Request('https://api.example.com')
authApi.useRequestInterceptor(addAuth)
authApi.useRequestInterceptor(addLang)
const publicApi = new Request('https://open.api.com')
// ── Or use per-request interceptors ──
api.get('/users', {}, {
requestInterceptors: [addAuth],
onSuccess: setUsers,
})
-
-Private Readonly basePrivate cachePrivate errorPrivate inflightPrivate requestPrivate responsePrivate buildPrivate buildPrivate buildPrivate buildOptional params: Record<PropertyKey, any>Private executePrivate executeOptional params: Record<PropertyKey, any>Private isPrivate joinPrivate normalizePrivate parseOptional data: unknownOptional data: unknownOptional data: unknownPrivate readPrivate removePrivate runPrivate runPrivate runA helper function that wraps a Promise and returns a tuple of [error, data]. -If the Promise resolves successfully, the first element of the tuple will be null, and the second element will be the resolved value. -If the Promise is rejected, the first element of the tuple will be the error, and the second element will be undefined.
-The Promise to wrap.
-A Promise that resolves to a tuple of [error, data].
-Returns the last portion of a path, similar to the Unix basename command. -Trims the query string if it exists. -Optionally, removes a suffix from the result.
-The path to get the basename from.
-Optional suffix: stringAn optional suffix to remove from the basename.
-The basename of the path.
-Takes a series of functions and returns a new function that runs these functions in reverse sequence. -If a function returns a Promise, the next function is called with the resolved value.
-Rest ...fns: Fn[]The functions to compose.
-A new function that takes any number of arguments and composes them through fns.
Rest ...args: any[]DefineDebounceFn is a function that creates a debounced function.
-The function to be debounced.
-Optional delay: numberThe delay in milliseconds to wait before the debounced function is called. Default is 500ms.
-Optional immediate: booleanWhether the debounced function should be called immediately before the delay. Default is false.
-defineSinglePromiseFn ensures that the provided function can only be called once at a time. -If the function is invoked while it's still executing, it returns the same promise, avoiding multiple calls.
-The function to be wrapped, which returns a promise.
-A function that ensures the provided function is only executed once and returns a promise.
-Formats a Date object according to the specified formatter string.
-The Date object to format
-The format string. Supports YYYY (year), MM (month), DD (day), hh (hours), mm (minutes), ss (seconds)
-Whether to use UTC time instead of local time
-The formatted date string
-const date = new Date(2024, 0, 1, 12, 30, 45);
formatDate(date, 'YYYY-MM-DD hh:mm:ss'); // Returns "2024-01-01 12:30:45"
formatDate(date, 'DD/MM/YYYY', true); // Returns "01/01/2024" in UTC
-
-Formats a date based on an array of numbers, with optional formatting string
-This function expects an array containing year, month, day, hour, minute, and second values. If the array is invalid or does not contain the necessary values, it logs a warning and returns 'Invalid Date'. -The function uses the slice method to create a new array containing only the first six elements, and decrements the month value by 1 to convert it from a 1-based index to a 0-based index used by the Date object. -It then creates a new Date object using the elements of the new array. If the date is invalid, it logs a warning and returns the date as a string. -Finally, the function formats the date according to an optional formatting string and returns the formatted date string.
-The array representing the date. This array should contain year, month, day, hour, minute, and second values.
-Optional formatter: stringOptional. A specific format string to format the date. Defaults to 'YYYY-MM-DD HH:mm:ss'.
-The formatted date string.
-Throws an error if the array is invalid or does not contain the necessary values.
-const dateArray = [2024, 2, 19, 10, 30, 0];
const formattedDate = formatDateByArray(dateArray, 'MMMM D, YYYY, h:mm A');
console.log(formattedDate);
-
-Formats a date based on a given timestamp.
-The timestamp to be formatted, in milliseconds.
-Optional formatter: stringOptional. A specific format string to format the date. Defaults to 'YYYY-MM-DD HH:mm:ss'.
-The formatted date string.
-Throws an error if the timestamp is invalid or out of range.
-const timestamp = new Date().getTime();
const formattedDate = formatDateByTimeStamp(timestamp);
console.log(formattedDate);
-
-Formats a date string into a specified date time format
-A string representing the date.
-Optional formatter: stringOptional. A specific format string to format the date. Defaults to 'YYYY-MM-DD HH:mm:ss'.
-The formatted date string.
-Throws an error if the date string is invalid or cannot be parsed into a Date object.
-const dateString = '2024-02-19T10:30:00Z';
const formattedDateTime = formatDateTimeByString(dateString, 'MMMM D, YYYY, h:mm A');
console.log(formattedDateTime);
-
-Formats an error object into a string representation.
-The error to format. It can be an Error instance, a string, or another object.
Optional defaultErrorString: string = ''The default error message if the error cannot be formatted.
-Optional opts: { Additional options.
-The maximum number of stack trace lines to include.
-The formatted error message.
-Creates a function factory with error handling capabilities
-Error handling function to process exceptions during execution
-Returns a new function that can execute target functions with automatic error handling
-Optional context: unknownOptional args: unknown[]const errorHandler = (error) => console.error(error);
const safeExecute = invokeWithErrorHandlingFactory(errorHandler);
// Execute regular function
safeExecute(() => { throw new Error('test') });
// Execute async function
safeExecute(async () => { throw new Error('async test') });
-
-need to split of primitive string
-split params
-split limit
-a new split array, length is num + 1
-Add the number of cuts based on the original split and return all subsets after the cut
-Takes a series of functions and returns a new function that runs these functions in sequence. -If a function returns a Promise, the next function is called with the resolved value.
-Rest ...fns: Fn[]The functions to pipe.
-A new function that takes any number of arguments and pipes them through fns.
Rest ...args: any[]Converts a query string to an object.
-The type of the URL string.
-The type of the object to return.
-The URL string to convert.
-The object representation of the query string in url.
`queryStringToObject('foo=1&bar=2&baz=3')`
-
-`queryStringToObject('foo=&bar=2&baz=3')`
-
-`queryStringToObject('foo[0]=1&foo[1]=2&baz=3')`
-
-Executes a given function repeatedly at a specified interval using setTimeout and clearTimeout.
-The function to be executed.
-The interval (in milliseconds) at which the function should be executed.
-A function that, when called, clears the interval and stops the execution of the given function.
-Executes a given function repeatedly at a specified interval using setTimeout and clearTimeout.
-The function to be executed.
-The interval (in milliseconds) at which the function should be executed.
-A function that, when called, clears the interval and stops the execution of the given function.
-A library of JavaScript tools
-npm install @cc-heart/utils
-
-import { capitalize } from '@cc-heart/utils'
capitalize('string') // String
-
-import { Request } from '@cc-heart/utils'
import type { RequestInterceptor } from '@cc-heart/utils'
-
-Prefer small focused instances over one instance with all interceptors. Combine them with factory functions:
-// ── Building blocks: interceptors are pure functions ──
const addAuth: RequestInterceptor = (config) => ({
...config,
headers: { ...config.headers, Authorization: `Bearer ${getToken()}` }
})
const addLang: RequestInterceptor = (config) => ({
...config,
headers: { ...config.headers, 'Accept-Language': 'zh-CN' }
})
const handleError = (err: unknown) => {
toast.error(err)
return err
}
// ── Compose: each instance handles one concern ──
const authApi = new Request('https://api.example.com')
authApi.useRequestInterceptor(addAuth)
authApi.useRequestInterceptor(addLang)
authApi.useErrorInterceptor(handleError)
const publicApi = new Request('https://open.api.com')
// ── Or use helper functions ──
function withInterceptors(
req: Request,
interceptors: RequestInterceptor[]
): Request {
interceptors.forEach((i) => req.useRequestInterceptor(i))
return req
}
function withBaseUrl(url: string): Request {
return new Request(url)
}
const api = withInterceptors(withBaseUrl('https://api.example.com'), [
addAuth,
addLang,
])
-
-const api = new Request('https://api.example.com')
// Style 1: async/await (recommended)
try {
const user = await api.get<User>('/users/1')
setUser(user)
} catch (e) {
if ((e as Error).name === 'AbortError') return // user cancelled
toast.error(e)
}
// Style 2: lifecycle callbacks (React setState friendly)
api.get('/users', {
onSuccess: setUsers,
onError: toast.error,
onFinally: () => setLoading(false),
})
// Style 3: promise chaining
api.get<number>('/count')
.then(n => n * 2)
.then(setCount)
.catch(toast.error)
// Style 4: mixed (await + callbacks, non-conflicting)
const data = await api.get('/users', { onFinally: () => setLoading(false) })
-
-// entities/user.ts
const api = new Request('/api')
export const UserApi = {
list: (page: number) =>
api.get<User[]>('/users', { page }),
get: (id: number) =>
api.get<User>(`/users/${id}`),
create: (data: CreateUserDto) =>
api.post<User>('/users', data, { onSuccess: () => toast.success('created') }),
}
// Usage
const users = await UserApi.list(1)
-
-const cachedApi = new Request('/api')
// cache and dedup are instance-level, different Request instances are isolated
const data1 = await cachedApi.get('/users', {}, { cache: { ttl: 5000 } })
const data2 = await cachedApi.get('/users', {}, { cache: { ttl: 5000 } }) // cache hit
const otherApi = new Request('/api') // isolated cache
-
-@cc-heart/utils is licensed under the MIT License.
Optional bodyOptional cacheResponse cache configuration. true = default TTL (5000ms).
Optional credentialsOptional dataOptional dispatcherOptional duplexOptional errorOptional headersOptional integrityOptional keepaliveOptional methodOptional modeOptional onOptional onDownload progress callback. Receives (loadedBytes, totalBytes).
-Optional onOptional onOptional onOptional paramsOptional redirectOptional referrerOptional referrerOptional requestOptional responseOptional retryMax retry count on failure. 0 = no retry.
-Optional retryDelay between retries in milliseconds.
-Optional signalOptional timeoutRequest timeout in milliseconds. 0 or undefined = no timeout.
-Optional windowConst Readonly ACCEPTED: 202Readonly AMBIGUOUS: 300Readonly BAD_Readonly BAD_Readonly CONFLICT: 409Readonly CONTINUE: 100Readonly CREATED: 201Readonly EARLYHINTS: 103Readonly EXPECTATION_Readonly FAILED_Readonly FORBIDDEN: 403Readonly FOUND: 302Readonly GATEWAY_Readonly GONE: 410Readonly HTTP_Readonly INTERNAL_Readonly I_Readonly LENGTH_Readonly METHOD_Readonly MISDIRECTED: 421Readonly MOVED_Readonly NON_Readonly NOT_Readonly NOT_Readonly NOT_Readonly NOT_Readonly NO_Readonly OK: 200Readonly PARTIAL_Readonly PAYLOAD_Readonly PAYMENT_Readonly PERMANENT_Readonly PRECONDITION_Readonly PRECONDITION_Readonly PROCESSING: 102Readonly PROXY_Readonly REQUESTED_Readonly REQUEST_Readonly RESET_Readonly SEE_Readonly SERVICE_Readonly SWITCHING_Readonly TEMPORARY_Readonly TOO_Readonly UNAUTHORIZED: 401Readonly UNPROCESSABLE_Readonly UNSUPPORTED_Readonly URI_Const Readonly 7Z: "application/x-7z-compressed"Readonly 7ZIP: "application/x-7z-compressed"Readonly ALZ: "application/x-alz"Readonly APK: "application/vnd.android.package-archive"Readonly AVI: "video/x-msvideo"Readonly BAT: "application/x-msdownload"Readonly BMP: "image/bmp"Readonly BZ2: "application/x-bzip2"Readonly C: "text/x-csrc"Readonly CPP: "text/x-c++src"Readonly CS: "text/plain"Readonly CSS: "text/css"Readonly CSV: "text/csv"Readonly DLL: "application/vnd.microsoft.portable-executable"Readonly DMG: "application/x-apple-diskimage"Readonly DOC: "application/msword"Readonly DOCX: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"Readonly DOT: "application/msword"Readonly DOTX: "application/vnd.openxmlformats-officedocument.wordprocessingml.template"Readonly DWG: "application/acad"Readonly DXF: "application/vnd.dxf"Readonly EML: "message/rfc822"Readonly EOT: "application/vnd.ms-fontobject"Readonly EPUB: "application/epub+zip"Readonly EXE: "application/vnd.microsoft.portable-executable"Readonly FLAC: "audio/flac"Readonly FLV: "video/x-flv"Readonly GIF: "image/gif"Readonly GO: "text/plain"Readonly GZ: "application/gzip"Readonly HTM: "text/html"Readonly HTML: "text/html"Readonly ICO: "image/vnd.microsoft.icon"Readonly JAVA: "text/x-java-source"Readonly JAVASCRIPT: "application/javascript"Readonly JPEG: "image/jpeg"Readonly JPG: "image/jpeg"Readonly JSON: "application/json"Readonly JSONLD: "application/ld+json"Readonly KT: "text/plain"Readonly M3Readonly M4A: "audio/mp4"Readonly MAP: "application/json"Readonly MKV: "video/x-matroska"Readonly MOV: "video/quicktime"Readonly MP3: "audio/mpeg"Readonly MP4: "video/mp4"Readonly MPD: "application/dash+xml"Readonly MSG: "application/vnd.ms-outlook"Readonly MSI: "application/x-msdownload"Readonly OBJ: "application/octet-stream"Readonly OGG: "audio/ogg"Readonly OTF: "font/otf"Readonly PDF: "application/pdf"Readonly PHP: "application/x-httpd-php"Readonly PNG: "image/png"Readonly POT: "application/vnd.ms-powerpoint"Readonly POTX: "application/vnd.openxmlformats-officedocument.presentationml.template"Readonly PPSX: "application/vnd.openxmlformats-officedocument.presentationml.slideshow"Readonly PPT: "application/vnd.ms-powerpoint"Readonly PPTX: "application/vnd.openxmlformats-officedocument.presentationml.presentation"Readonly PY: "text/x-python"Readonly RAR: "application/vnd.rar"Readonly RB: "application/x-ruby"Readonly RTF: "application/rtf"Readonly STL: "application/sla"Readonly SVG: "image/svg+xml"Readonly SWF: "application/x-shockwave-flash"Readonly SWIFT: "text/x-swift"Readonly TAR: "application/x-tar"Readonly TORRENT: "application/x-bittorrent"Readonly TS: "video/mp2t"Readonly TTF: "font/ttf"Readonly TXT: "text/plain"Readonly WASM: "application/wasm"Readonly WAV: "audio/wav"Readonly WEBM: "video/webm"Readonly WEBP: "image/webp"Readonly WMV: "video/x-ms-wmv"Readonly WOFF: "font/woff"Readonly WOFF2: "font/woff2"Readonly XLS: "application/vnd.ms-excel"Readonly XLSM: "application/vnd.ms-excel.sheet.macroEnabled.12"Readonly XLSX: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"Readonly XLT: "application/vnd.ms-excel"Readonly XML: "application/xml"Readonly ZIP: "application/zip"Const Readonly ALL: "ALL"Readonly DELETE: "DELETE"Readonly GET: "GET"Readonly HEAD: "HEAD"Readonly OPTIONS: "OPTIONS"Readonly PATCH: "PATCH"Readonly POST: "POST"Readonly PUT: "PUT"Readonly SEARCH: "SEARCH"
Logger class for formatted and leveled log output.
-