@alwatr/fetch 10.0.3 → 10.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js.map CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/core.ts", "../src/error.ts", "../src/main.ts"],
3
+ "sources": ["../src/error.ts", "../src/options.ts", "../src/retry.ts", "../src/timeout.ts", "../src/dedupe.ts", "../src/cache.ts", "../src/fetch.ts"],
4
4
  "sourcesContent": [
5
- "import {delay} from '@alwatr/delay';\nimport {getGlobalThis} from '@alwatr/global-this';\nimport {hasOwn} from '@alwatr/has-own';\nimport {HttpStatusCodes, MimeTypes} from '@alwatr/http-primer';\nimport {createLogger} from '@alwatr/logger';\nimport {parseDuration} from '@alwatr/parse-duration';\n\nimport {FetchError} from './error.js';\n\nimport type {AlwatrFetchOptions_, FetchOptions} from './type.js';\n\nexport const logger_ = createLogger('@alwatr/fetch');\n\nconst globalThis_ = getGlobalThis();\n\n/**\n * A boolean flag indicating whether the browser's Cache API is supported.\n */\nexport const cacheSupported = /* #__PURE__ */ hasOwn(globalThis_, 'caches');\n\n/**\n * A simple in-memory storage for tracking and managing duplicate in-flight requests.\n * The key is a unique identifier for the request (e.g., method + URL + body),\n * and the value is the promise of the ongoing fetch operation.\n */\nconst duplicateRequestStorage_: Record<string, Promise<Response>> = {};\n\n/**\n * Default options for all fetch requests. These can be overridden by passing\n * a custom `options` object to the `fetch` function.\n */\nconst defaultFetchOptions: AlwatrFetchOptions_ = {\n method: 'GET',\n headers: {},\n timeout: 8_000,\n retry: 3,\n retryDelay: 1_000,\n removeDuplicate: 'never',\n cacheStrategy: 'network_only',\n cacheStorageName: 'fetch_cache',\n};\n\n/**\n * Internal-only fetch options type, which includes the URL and ensures all\n * optional properties from AlwatrFetchOptions_ are present.\n */\ntype FetchOptions__ = AlwatrFetchOptions_ & Omit<RequestInit, 'headers'> & {url: string};\n\n/**\n * Processes and sanitizes the fetch options.\n *\n * @param {string} url - The URL to fetch.\n * @param {FetchOptions} options - The user-provided options.\n * @returns {FetchOptions__} The processed and complete fetch options.\n * @private\n */\nexport function _processOptions(url: string, options: FetchOptions): FetchOptions__ {\n DEV_MODE && logger_.logMethodArgs?.('_processOptions', {url, options});\n\n const options_: FetchOptions__ = {\n ...defaultFetchOptions,\n ...options,\n // Headers must be private per request: the object is mutated below\n // (content-type, authorization), and both the module-level default and a\n // caller-supplied object would otherwise accumulate headers across calls\n // — leaking one request's credential onto every later one.\n headers: {\n ...defaultFetchOptions.headers,\n ...options.headers,\n },\n url,\n };\n\n options_.window ??= null;\n\n if (options_.removeDuplicate === 'auto') {\n options_.removeDuplicate = cacheSupported ? 'until_load' : 'always';\n }\n\n // Append query parameters to the URL if they are provided and the URL doesn't already have them.\n if (options_.url.lastIndexOf('?') === -1 && options_.queryParams != null) {\n const queryParams = options_.queryParams;\n // prettier-ignore\n const queryArray = Object\n .keys(queryParams)\n .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(String(queryParams[key]))}`);\n\n if (queryArray.length > 0) {\n options_.url += '?' + queryArray.join('&');\n }\n }\n\n // If `bodyJson` is provided, stringify it and set the appropriate 'Content-Type' header.\n if (options_.bodyJson !== undefined) {\n options_.body = JSON.stringify(options_.bodyJson);\n options_.headers['content-type'] = MimeTypes.JSON;\n }\n\n // Set the 'Authorization' header for bearer tokens or Alwatr's authentication scheme.\n if (options_.bearerToken !== undefined) {\n options_.headers.authorization = `Bearer ${options_.bearerToken}`;\n } else if (options_.alwatrAuth !== undefined) {\n options_.headers.authorization = `Alwatr ${options_.alwatrAuth.userId}:${options_.alwatrAuth.userToken}`;\n }\n\n DEV_MODE && logger_.logProperty?.('fetch.options', options_);\n\n return options_;\n}\n\n/**\n * Manages caching strategies for the fetch request.\n * If the strategy is `network_only`, it bypasses caching and proceeds to the next step.\n * Otherwise, it interacts with the browser's Cache API based on the selected strategy.\n *\n * @param {FetchOptions__} options - The fully configured fetch options.\n * @returns {Promise<Response>} A promise resolving to a `Response` object, either from the cache or the network.\n * @private\n */\nexport async function handleCacheStrategy_(options: FetchOptions__): Promise<Response> {\n if (options.cacheStrategy === 'network_only') {\n return handleRemoveDuplicate_(options);\n }\n // else\n\n DEV_MODE && logger_.logMethod?.('handleCacheStrategy_');\n\n if (!cacheSupported) {\n DEV_MODE\n && logger_.incident?.('fetch', 'fetch_cache_strategy_unsupported', {\n cacheSupported,\n });\n // Fallback to network_only if Cache API is not available.\n options.cacheStrategy = 'network_only';\n return handleRemoveDuplicate_(options);\n }\n // else\n\n const cacheStorage = await caches.open(options.cacheStorageName);\n\n const request = new Request(options.url, options);\n\n switch (options.cacheStrategy) {\n case 'cache_first': {\n const cachedResponse = await cacheStorage.match(request);\n if (cachedResponse != null) {\n return cachedResponse;\n }\n // else\n\n const response = await handleRemoveDuplicate_(options);\n if (response.ok) {\n cacheStorage.put(request, response.clone());\n }\n return response;\n }\n\n case 'cache_only': {\n const cachedResponse = await cacheStorage.match(request);\n if (cachedResponse == null) {\n throw new FetchError('cache_not_found', 'Resource not found in cache');\n }\n // else\n\n return cachedResponse;\n }\n\n case 'network_first': {\n try {\n const networkResponse = await handleRemoveDuplicate_(options);\n if (networkResponse.ok) {\n cacheStorage.put(request, networkResponse.clone());\n }\n return networkResponse;\n } catch (err) {\n const cachedResponse = await cacheStorage.match(request);\n if (cachedResponse != null) {\n return cachedResponse;\n }\n // else\n\n throw err;\n }\n }\n\n case 'update_cache': {\n const networkResponse = await handleRemoveDuplicate_(options);\n if (networkResponse.ok) {\n cacheStorage.put(request, networkResponse.clone());\n }\n return networkResponse;\n }\n\n case 'stale_while_revalidate': {\n const cachedResponse = await cacheStorage.match(request);\n const fetchedResponsePromise = handleRemoveDuplicate_(options).then((networkResponse) => {\n if (networkResponse.ok) {\n cacheStorage.put(request, networkResponse.clone());\n if (typeof options.revalidateCallback === 'function') {\n setTimeout(options.revalidateCallback, 0, networkResponse.clone());\n }\n }\n return networkResponse;\n });\n\n return cachedResponse ?? fetchedResponsePromise;\n }\n\n default: {\n return handleRemoveDuplicate_(options);\n }\n }\n}\n\n/**\n * Handles duplicate request elimination.\n *\n * It creates a unique key based on the request method, URL, and body. If a request with the\n * same key is already in flight, it returns the promise of the existing request instead of\n * creating a new one. This prevents redundant network calls for identical parallel requests.\n *\n * @param {FetchOptions__} options - The fully configured fetch options.\n * @returns {Promise<Response>} A promise resolving to a cloned `Response` object.\n * @private\n */\nasync function handleRemoveDuplicate_(options: FetchOptions__): Promise<Response> {\n if (options.removeDuplicate === 'never') {\n return handleRetryPattern_(options);\n }\n // else\n\n DEV_MODE && logger_.logMethod?.('handleRemoveDuplicate_');\n\n // Create a unique key for the request. Including the body is crucial to differentiate\n // between requests to the same URL but with different payloads (e.g., POST requests).\n const bodyString = typeof options.body === 'string' ? options.body : '';\n const cacheKey = `${options.method} ${options.url} ${bodyString}`;\n\n // If a request with the same key doesn't exist, create it and store its promise.\n duplicateRequestStorage_[cacheKey] ??= handleRetryPattern_(options);\n\n try {\n // Await the shared promise to get the response.\n const response = await duplicateRequestStorage_[cacheKey];\n\n // Clean up the stored promise based on the removal strategy.\n if (duplicateRequestStorage_[cacheKey] != null) {\n if (response.ok !== true || options.removeDuplicate === 'until_load') {\n // Remove after completion for 'until_load' or if the request failed.\n delete duplicateRequestStorage_[cacheKey];\n }\n }\n\n // Return a clone of the response, so each caller can consume the body independently.\n return response.clone();\n } catch (err) {\n // If the request fails, remove it from storage to allow for retries.\n delete duplicateRequestStorage_[cacheKey];\n throw err;\n }\n}\n\n/**\n * Implements a retry mechanism for the fetch request.\n * If the request fails due to a server error (status >= 500) or a timeout,\n * it will be retried up to the specified number of times.\n *\n * @param {FetchOptions__} options - The fully configured fetch options.\n * @returns {Promise<Response>} A promise that resolves to the final `Response` after all retries.\n * @private\n */\nasync function handleRetryPattern_(options: FetchOptions__): Promise<Response> {\n if (!(options.retry > 1)) {\n return handleTimeout_(options);\n }\n // else\n\n DEV_MODE && logger_.logMethod?.('handleRetryPattern_');\n options.retry--;\n\n const externalAbortSignal = options.signal;\n\n try {\n const response = await handleTimeout_(options);\n\n if (!response.ok && response.status >= HttpStatusCodes.Error_Server_500_Internal_Server_Error) {\n // only retry for server errors (5xx)\n throw new FetchError('http_error', `HTTP error! status: ${response.status} ${response.statusText}`, response);\n }\n\n return response;\n } catch (err) {\n DEV_MODE && logger_.accident('fetch', 'fetch_failed_retry', err);\n\n // Do not retry if the browser is offline.\n if (globalThis_.navigator?.onLine === false) {\n DEV_MODE && logger_.accident('handleRetryPattern_', 'offline', 'Skip retry because offline');\n throw err;\n }\n\n await delay.by(options.retryDelay);\n\n // Restore the original signal for the next attempt.\n options.signal = externalAbortSignal;\n return handleRetryPattern_(options);\n }\n}\n\n/**\n * Wraps the native fetch call with a timeout mechanism.\n *\n * It uses an `AbortController` to abort the request if it does not complete\n * within the specified `timeout` duration. It also respects external abort signals.\n *\n * @param {FetchOptions__} options - The fully configured fetch options.\n * @returns {Promise<Response>} A promise that resolves with the `Response` or rejects on timeout.\n * @private\n */\nfunction handleTimeout_(options: FetchOptions__): Promise<Response> {\n if (options.timeout === 0) {\n // If timeout is disabled, call fetch directly.\n return globalThis_.fetch(options.url, options);\n }\n\n DEV_MODE && logger_.logMethod?.('handleTimeout_');\n\n return new Promise((resolved, reject) => {\n const abortController = typeof AbortController === 'function' ? new AbortController() : null;\n const externalAbortSignal = options.signal;\n options.signal = abortController?.signal;\n\n // If an external AbortSignal is provided, listen to it and propagate the abort.\n if (abortController !== null && externalAbortSignal != null) {\n externalAbortSignal.addEventListener('abort', () => abortController.abort(), {once: true});\n }\n\n const timeoutId = setTimeout(() => {\n reject(new FetchError('timeout', 'fetch_timeout'));\n abortController?.abort('fetch_timeout');\n }, parseDuration(options.timeout!));\n\n globalThis_\n .fetch(options.url, options)\n .then((response) => resolved(response))\n .catch((reason) => reject(reason))\n .finally(() => {\n // Clean up the timeout to prevent it from firing after the request has completed.\n clearTimeout(timeoutId);\n });\n });\n}\n",
6
- "import type {JsonObject} from '@alwatr/type-helper';\nimport type {FetchErrorReason} from './type.js';\n\n/**\n * Custom error class for fetch-related failures.\n *\n * This error is thrown when a fetch request fails, either due to a network issue\n * or an HTTP error status (i.e., `response.ok` is `false`). It enriches the\n * standard `Error` object with the `response` and the parsed `data` from the\n * response body, allowing for more detailed error handling.\n *\n * @example\n * ```typescript\n * const [response, error] = await fetch('/api/endpoint');\n * if (error) {\n * console.error(`Request failed with status ${error.response?.status}`);\n * console.error('Server response:', error.data);\n * }\n * ```\n */\nexport class FetchError extends Error {\n /**\n * The original `Response` object.\n * This is useful for accessing headers and other response metadata.\n * It will be `undefined` for non-HTTP errors like network failures or timeouts.\n */\n public response?: Response;\n\n /**\n * The parsed body of the error response, typically a JSON object.\n * It will be `undefined` for non-HTTP errors.\n */\n public data?: JsonObject | string;\n\n /**\n * The specific reason for the fetch failure.\n */\n public reason: FetchErrorReason;\n\n constructor(reason: FetchErrorReason, message: string, response?: Response, data?: JsonObject | string) {\n super(message);\n this.name = 'FetchError';\n this.reason = reason;\n this.response = response;\n this.data = data;\n }\n}\n",
7
- "/**\n * @module @alwatr/fetch\n *\n * An enhanced, lightweight, and dependency-free wrapper for the native `fetch`\n * API. It provides modern features like caching strategies, request retries,\n * timeouts, and duplicate request handling.\n */\n\nimport type {JsonObject} from '@alwatr/type-helper';\nimport {_processOptions, handleCacheStrategy_, logger_, cacheSupported} from './core.js';\nimport {FetchError} from './error.js';\n\nimport type {FetchJsonOptions, FetchOptions, FetchResponse} from './type.js';\n\nexport {cacheSupported};\nexport * from './error.js';\nexport type * from './type.js';\n\n/**\n * An enhanced wrapper for the native `fetch` function.\n *\n * This function extends the standard `fetch` with additional features such as:\n * - **Timeout**: Aborts the request if it takes too long.\n * - **Retry Pattern**: Automatically retries the request on failure (e.g., server errors or network issues).\n * - **Duplicate Request Handling**: Prevents sending multiple identical requests in parallel.\n * - **Cache Strategies**: Provides various caching mechanisms using the browser's Cache API.\n * - **Simplified API**: Offers convenient options for adding query parameters, JSON bodies, and auth tokens.\n *\n * @see {@link FetchOptions} for a detailed list of available options.\n *\n * @param {string} url - The URL to fetch.\n * @param {FetchOptions} options - Optional configuration for the fetch request.\n * @returns {Promise<FetchResponse>} A promise that resolves to a tuple. On\n * success, it returns `[response, null]`. On failure, it returns `[null,\n * FetchError]`.\n *\n * @example\n * ```typescript\n * import {fetch} from '@alwatr/fetch';\n *\n * async function fetchProducts() {\n * const [response, error] = await fetch('/api/products', {\n * queryParams: { limit: 10 },\n * timeout: 5_000,\n * });\n *\n * if (error) {\n * console.error('Request failed:', error.reason);\n * return;\n * }\n *\n * // At this point, response is guaranteed to be valid and ok.\n * const data = await response.json();\n * console.log('Products:', data);\n * }\n *\n * fetchProducts();\n * ```\n */\nexport async function fetch(url: string, options: FetchOptions = {}): Promise<FetchResponse> {\n DEV_MODE && logger_.logMethodArgs?.('fetch', {url, options});\n\n const options_ = _processOptions(url, options);\n\n try {\n // Start the fetch lifecycle, beginning with the cache strategy.\n const response = await handleCacheStrategy_(options_);\n\n if (!response.ok) {\n throw new FetchError('http_error', `HTTP error! status: ${response.status} ${response.statusText}`, response);\n }\n\n return [response, null];\n } catch (err) {\n let error: FetchError;\n\n if (err instanceof FetchError) {\n error = err;\n\n if (error.response !== undefined && error.data === undefined) {\n const bodyText = await error.response.text().catch(() => '');\n\n if (bodyText.trim().length > 0) {\n try {\n // Try to parse as JSON\n error.data = JSON.parse(bodyText);\n } catch {\n error.data = bodyText;\n }\n }\n }\n } else if (err instanceof Error) {\n if (err.name === 'AbortError') {\n error = new FetchError('aborted', err.message);\n } else {\n error = new FetchError('network_error', err.message);\n }\n } else {\n error = new FetchError('unknown_error', String(err ?? 'unknown_error'));\n }\n\n logger_.error('fetch', error.reason, {error});\n return [null, error];\n }\n}\n\nfetch.version = __package_version__;\n\n/**\n * An enhanced wrapper for the native `fetch` function that automatically parses JSON responses.\n *\n * This function extends the standard `fetch` with the same features (timeout, retry, caching, etc.)\n * and automatically parses the response body as JSON. It returns a tuple with the parsed data or an error.\n *\n * @template T - The expected type of the JSON response data.\n *\n * @param {string} url - The URL to fetch.\n * @param {FetchOptions} options - Optional configuration for the fetch request.\n * @returns {Promise<[T, null] | [null, FetchError]>} A promise that resolves to a tuple.\n * On success, it returns `[data, null]` where data is the parsed JSON.\n * On failure, it returns `[null, FetchError]`.\n *\n * @example\n * ```typescript\n * import {fetchJson} from '@alwatr/fetch';\n *\n * interface Product {\n * ok: true;\n * id: number;\n * name: string;\n * price: number;\n * }\n *\n * async function getProduct(id: number) {\n * const [data, error] = await fetchJson<Product>(`/api/products/${id}`, {\n * timeout: 5_000,\n * cacheStrategy: 'cache_first',\n * requireResponseJsonWithOkTrue: true,\n * });\n *\n * if (error) {\n * console.error('Failed to fetch product:', error.reason);\n * return;\n * }\n *\n * // data is now typed as Product and guaranteed to be valid\n * console.log('Product name:', data.name);\n * }\n * ```\n */\nexport async function fetchJson<T extends JsonObject = JsonObject>(\n url: string,\n options: FetchJsonOptions = {},\n): Promise<[T, null] | [null, FetchError]> {\n DEV_MODE && logger_.logMethodArgs?.('fetchJson', {url, options});\n\n const [response, error] = await fetch(url, options);\n\n if (error) {\n return [null, error];\n }\n\n const bodyText = await response.text().catch(() => '');\n if (bodyText.trim().length === 0) {\n const parseError = new FetchError(\n 'json_parse_error',\n 'Response body is empty, cannot parse JSON',\n response,\n bodyText,\n );\n logger_.error('fetchJson', parseError.reason, {error: parseError});\n return [null, parseError];\n }\n\n try {\n const data = JSON.parse(bodyText) as T;\n if (options.requireJsonResponseWithOkTrue && data.ok !== true) {\n const parseError = new FetchError(\n 'json_response_error',\n 'Response JSON \"ok\" property is not true',\n response,\n data,\n );\n logger_.error('fetchJson', parseError.reason, {error: parseError});\n return [null, parseError];\n }\n return [data, null];\n } catch (err) {\n const parseError = new FetchError(\n 'json_parse_error',\n err instanceof Error ? err.message : 'Failed to parse JSON response',\n response,\n bodyText,\n );\n logger_.error('fetchJson', parseError.reason, {error: parseError});\n return [null, parseError];\n }\n}\n"
5
+ "import {HttpStatusCodes} from '@alwatr/http-primer';\nimport type {FetchErrorReason} from './type.js';\n\n/**\n * Maps an HTTP status code to a semantic `FetchErrorReason`.\n *\n * @param status - The HTTP response status code.\n * @returns The mapped `FetchErrorReason`.\n *\n * @example\n * ```typescript\n * httpStatusToErrorReason(401); // 'unauthorized'\n * httpStatusToErrorReason(404); // 'not_found'\n * httpStatusToErrorReason(500); // 'server_error'\n * ```\n */\nexport function httpStatusToErrorReason(status: number): FetchErrorReason {\n switch (status) {\n case HttpStatusCodes.Error_Client_400_Bad_Request:\n return 'bad_request';\n case HttpStatusCodes.Error_Client_401_Unauthorized:\n return 'unauthorized';\n case HttpStatusCodes.Error_Client_403_Forbidden:\n return 'forbidden';\n case HttpStatusCodes.Error_Client_404_Not_Found:\n return 'not_found';\n case HttpStatusCodes.Error_Client_408_Request_Timeout:\n return 'request_timeout';\n case HttpStatusCodes.Error_Client_409_Conflict:\n return 'conflict';\n case HttpStatusCodes.Error_Client_413_Payload_Too_Large:\n return 'payload_too_large';\n case HttpStatusCodes.Error_Client_422_Unprocessable_Entity:\n return 'unprocessable_content';\n case HttpStatusCodes.Error_Client_429_Too_Many_Requests:\n return 'rate_limited';\n default:\n if (status >= 500 && status < 600) {\n return 'server_error';\n }\n return 'http_error';\n }\n}\n\n/**\n * Custom error class for fetch-related failures.\n *\n * This error is returned in the `[null, FetchError]` tuple when a request fails.\n * It enriches the standard `Error` with the `response`, the parsed `data` body,\n * and the specific `reason` enum.\n *\n * @example\n * ```typescript\n * const [response, error] = await fetch('/api/endpoint');\n * if (error) {\n * if (error.reason === 'unauthorized') {\n * redirectToLogin();\n * } else if (error.reason === 'server_error') {\n * showToast('Server unavailable, please try again later');\n * }\n * }\n * ```\n */\nexport class FetchError extends Error {\n /**\n * The original `Response` object, if one was received.\n */\n public response?: Response;\n\n /**\n * The parsed body of the error response, if available (JSON object, string, etc.).\n */\n public data?: unknown;\n\n /**\n * The specific semantic reason for the fetch failure.\n */\n public reason: FetchErrorReason;\n\n /**\n * Helper getter for the HTTP status code.\n */\n get status(): number | undefined {\n return this.response?.status;\n }\n\n /**\n * Always `false` to indicate error status.\n */\n readonly ok: false = false;\n\n constructor(reason: FetchErrorReason, message: string, response?: Response, data?: unknown) {\n super(message);\n this.name = 'FetchError';\n this.reason = reason;\n this.response = response;\n this.data = data;\n }\n}\n",
6
+ "import {MimeTypes, type HttpMethod} from '@alwatr/http-primer';\nimport {createLogger} from '@alwatr/logger';\nimport {getGlobalThis} from '@alwatr/global-this';\nimport {parseDuration} from '@alwatr/parse-duration';\n\nimport type {AlwatrFetchOptions_, FetchOptions, InternalFetchOptions_, QueryParams} from './type.js';\n\nexport const logger_ = createLogger('@alwatr/fetch');\n\nexport const globalThis_ = getGlobalThis();\n\n/**\n * Immutable default options for all fetch requests.\n */\nexport const defaultFetchOptions: Readonly<AlwatrFetchOptions_> = {\n method: 'GET',\n timeout: 8_000,\n retry: 3,\n retryDelay: 1_000,\n removeDuplicate: 'never',\n cacheStrategy: 'network_only',\n cacheStorageName: 'fetch_cache',\n // headers: {}, // --- IGNORED ---\n};\n\n/**\n * Normalizes any standard `HeadersInit` into a fresh, isolated lowercase string record.\n *\n * @param headers - User-provided headers (plain object, Headers instance, or entries array).\n * @param baseHeaders - Optional base headers to merge with the user-provided headers.\n * @returns An isolated `Record<string, string>`.\n */\nexport function normalizeHeaders_(\n headers?: HeadersInit,\n baseHeaders: Record<string, string> = {},\n): Record<string, string> {\n if (headers == null) {\n return baseHeaders;\n }\n\n if (typeof Headers !== 'undefined' && headers instanceof Headers) {\n headers.forEach((value, key) => {\n baseHeaders[key.toLowerCase()] = value;\n });\n return baseHeaders;\n }\n\n if (Array.isArray(headers)) {\n for (const [key, value] of headers) {\n if (typeof key === 'string' && typeof value === 'string') {\n baseHeaders[key.toLowerCase()] = value;\n }\n }\n return baseHeaders;\n }\n\n if (typeof headers === 'object') {\n for (const key of Object.keys(headers)) {\n const val = (headers as Record<string, unknown>)[key];\n if (val != null) {\n baseHeaders[key.toLowerCase()] = String(val);\n }\n }\n }\n\n return baseHeaders;\n}\n\n/**\n * Serializes query parameters into a query string.\n *\n * @param queryParams - Dictionary of query parameters.\n * @returns Serialized URL query string (without leading `?` or `&`).\n */\nexport function serializeQueryParams_(queryParams: QueryParams): string {\n const parts: string[] = [];\n\n for (const key of Object.keys(queryParams)) {\n const value = queryParams[key];\n if (value == null) {\n continue;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item != null) {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(item))}`);\n }\n }\n } else {\n parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);\n }\n }\n\n return parts.join('&');\n}\n\n/**\n * Appends query parameters to a URL, correctly respecting existing query parameters and hash anchors.\n *\n * @param url - The target URL.\n * @param queryParams - Query parameters to append.\n * @returns The resulting URL string.\n */\nexport function appendQueryParams_(url: string, queryParams?: QueryParams): string {\n if (queryParams == null) {\n return url;\n }\n\n const queryString = serializeQueryParams_(queryParams);\n if (queryString.length === 0) {\n return url;\n }\n\n // Handle hash fragment if present in URL\n let baseUrl = url;\n let hashPart = '';\n const hashIndex = url.indexOf('#');\n\n if (hashIndex !== -1) {\n baseUrl = url.slice(0, hashIndex);\n hashPart = url.slice(hashIndex);\n }\n\n const separator = baseUrl.includes('?') ? '&' : '?';\n return `${baseUrl}${separator}${queryString}${hashPart}`;\n}\n\n/**\n * Processes, sanitizes, and normalizes user-provided fetch options into a complete, isolated options object.\n *\n * @param url - The target URL.\n * @param options - User-provided options.\n * @returns Internal, complete, and isolated fetch options.\n * @internal\n */\nexport function processOptions_(url: string, options: FetchOptions = {}): InternalFetchOptions_ {\n DEV_MODE && logger_.logMethod?.('processOptions_');\n\n const processedUrl = appendQueryParams_(url, options.queryParams);\n\n const options_: InternalFetchOptions_ = {\n ...defaultFetchOptions,\n ...options,\n headers: normalizeHeaders_(options.headers),\n url: processedUrl,\n method: (options.method?.toUpperCase() as HttpMethod) ?? defaultFetchOptions.method,\n timeout: parseDuration(options.timeout ?? defaultFetchOptions.timeout),\n retryDelay: parseDuration(options.retryDelay ?? defaultFetchOptions.retryDelay),\n retry:\n typeof options.retry === 'number' && Number.isFinite(options.retry) ?\n Math.max(1, Math.floor(options.retry))\n : defaultFetchOptions.retry,\n };\n\n options_.window ??= null;\n\n // Cache API Preconditions: requires Cache API runtime support and cacheable HTTP method (GET/HEAD)\n if (\n options_.cacheStrategy !== 'network_only'\n && (typeof caches === 'undefined' || (options_.method !== 'GET' && options_.method !== 'HEAD'))\n ) {\n DEV_MODE\n && logger_.incident?.('processOptions_', 'fetch_cache_strategy_unsupported', {\n method: options_.method,\n cacheStrategy: options_.cacheStrategy,\n hasCaches: typeof caches !== 'undefined',\n });\n options_.cacheStrategy = 'network_only';\n }\n\n // Deduplication auto selection\n if (options_.removeDuplicate === 'auto') {\n options_.removeDuplicate = typeof caches !== 'undefined' ? 'until_load' : 'always';\n }\n\n // JSON Body serialization\n if (options.bodyJson != null) {\n options_.body = JSON.stringify(options.bodyJson);\n options_.headers['content-type'] = MimeTypes.JSON;\n }\n\n // Authorization header configuration\n if (options.bearerToken != null) {\n options_.headers.authorization = `Bearer ${options.bearerToken}`;\n } else if (options.alwatrAuth != null) {\n options_.headers.authorization = `Alwatr ${options.alwatrAuth.userId}:${options.alwatrAuth.userToken}`;\n }\n\n return options_;\n}\n",
7
+ "import {delay} from '@alwatr/delay';\nimport {getGlobalThis} from '@alwatr/global-this';\nimport {HttpStatusCodes} from '@alwatr/http-primer';\nimport {FetchError} from './error.js';\nimport {logger_} from './options.js';\nimport {handleTimeout_} from './timeout.js';\n\nimport type {InternalFetchOptions_} from './type.js';\n\nconst globalThis_ = getGlobalThis();\n\n/**\n * Checks whether an HTTP response status code is retryable.\n *\n * Retryable statuses:\n * - Any 5xx Server Error (500, 502, 503, 504, ...)\n * - 408 Request Timeout\n * - 429 Too Many Requests\n */\nexport function isRetryableStatus_(status: number): boolean {\n return (\n status >= HttpStatusCodes.Error_Server_500_Internal_Server_Error\n || status === HttpStatusCodes.Error_Client_408_Request_Timeout\n || status === HttpStatusCodes.Error_Client_429_Too_Many_Requests\n );\n}\n\n/**\n * Parses the `Retry-After` header value (in seconds or HTTP-date) if present.\n *\n * @param response - The HTTP Response object.\n * @returns Delay duration in milliseconds, or undefined if absent/invalid.\n */\nexport function parseRetryAfterHeader_(response?: Response): number | undefined {\n const retryAfter = response?.headers?.get('retry-after');\n if (!retryAfter) return undefined;\n\n const seconds = Number(retryAfter);\n if (!isNaN(seconds) && seconds > 0) {\n return seconds * 1000;\n }\n\n const dateMs = Date.parse(retryAfter);\n if (!isNaN(dateMs)) {\n const diff = dateMs - Date.now();\n return diff > 0 ? diff : 0;\n }\n\n return undefined;\n}\n\n/**\n * Executes a fetch request with automatic retries on transient errors (5xx, 429, 408, network failures, timeouts).\n *\n * @param options - Processed internal fetch options.\n * @returns A promise resolving to the final `Response` after retry cycles.\n * @internal\n */\nexport async function handleRetryPattern_(options: InternalFetchOptions_): Promise<Response> {\n if (options.retry <= 1) {\n return handleTimeout_(options);\n }\n\n DEV_MODE && logger_.logMethod?.('handleRetryPattern_');\n options.retry--;\n\n let response: Response;\n try {\n response = await handleTimeout_(options);\n\n if (response.ok || !isRetryableStatus_(response.status)) {\n return response;\n }\n } catch (err) {\n DEV_MODE && logger_.accident('fetch', 'fetch_failed_retry', err);\n\n // Never retry if the request was intentionally aborted\n if (options.signal?.aborted || (err instanceof FetchError && err.reason === 'aborted')) {\n throw err;\n }\n\n // Do not retry if the runtime is offline\n if (globalThis_.navigator?.onLine === false) {\n DEV_MODE && logger_.accident('handleRetryPattern_', 'offline', 'Skip retry because offline');\n throw err;\n }\n\n await delay.by(options.retryDelay);\n\n return handleRetryPattern_(options);\n }\n\n // Handle transient retryable HTTP status (5xx, 429, 408)\n DEV_MODE && logger_.accident('fetch', 'fetch_failed_retry', {status: response.status});\n\n if (globalThis_.navigator?.onLine === false) {\n DEV_MODE && logger_.accident('handleRetryPattern_', 'offline', 'Skip retry because offline');\n return response;\n }\n\n const retryDelay = parseRetryAfterHeader_(response) ?? options.retryDelay;\n\n await delay.by(retryDelay);\n\n return handleRetryPattern_(options);\n}\n",
8
+ "import {getGlobalThis} from '@alwatr/global-this';\nimport {FetchError} from './error.js';\nimport {logger_} from './options.js';\n\nimport type {InternalFetchOptions_} from './type.js';\n\nconst globalThis_ = getGlobalThis();\n\n/**\n * Executes a native `fetch` wrapped with an `AbortController` timeout.\n *\n * Checks for pre-aborted external signals, respects external cancellation,\n * and guarantees listener and timer cleanup on completion.\n *\n * @param options - Processed internal fetch options.\n * @returns A promise resolving to the native `Response` or rejecting with `FetchError`.\n * @internal\n */\nexport function handleTimeout_(options: InternalFetchOptions_): Promise<Response> {\n const externalSignal = options.signal;\n\n // Immediate abort check: If signal is already aborted, reject immediately without network overhead\n if (externalSignal?.aborted) {\n DEV_MODE && logger_.incident?.('handleTimeout_', 'already_aborted', {reason: externalSignal.reason});\n return Promise.reject(new FetchError('aborted', 'The operation was aborted'));\n }\n\n // If timeout is disabled (0), invoke native fetch directly with external signal\n if (options.timeout === 0) {\n return globalThis_.fetch(options.url, options as RequestInit);\n }\n\n DEV_MODE && logger_.logMethod?.('handleTimeout_');\n\n return new Promise((resolve, reject) => {\n const abortController = typeof AbortController === 'function' ? new AbortController() : null;\n\n let onExternalAbort: (() => void) | undefined;\n\n if (abortController !== null) {\n options.signal = abortController.signal;\n\n if (externalSignal != null) {\n onExternalAbort = () => {\n abortController.abort(externalSignal.reason);\n };\n externalSignal.addEventListener('abort', onExternalAbort, {once: true});\n }\n }\n\n let timeoutFired = false;\n\n const timeoutId = setTimeout(() => {\n timeoutFired = true;\n abortController?.abort('fetch_timeout');\n reject(new FetchError('timeout', 'fetch_timeout'));\n }, options.timeout);\n\n globalThis_\n .fetch(options.url, options as RequestInit)\n .then((response) => {\n if (!timeoutFired) {\n resolve(response);\n }\n })\n .catch((err: unknown) => {\n if (timeoutFired) {\n return;\n }\n\n if (externalSignal?.aborted || (err instanceof Error && err.name === 'AbortError')) {\n reject(new FetchError('aborted', 'The operation was aborted'));\n } else {\n reject(err);\n }\n })\n .finally(() => {\n clearTimeout(timeoutId);\n options.signal = externalSignal;\n if (externalSignal != null && onExternalAbort != null) {\n externalSignal.removeEventListener('abort', onExternalAbort);\n }\n });\n });\n}\n",
9
+ "import {logger_} from './options.js';\nimport {handleRetryPattern_} from './retry.js';\n\nimport type {InternalFetchOptions_} from './type.js';\n\n/**\n * Storage for tracking in-flight duplicate requests.\n */\nconst duplicateRequestStorage_: Map<string, Promise<Response>> = new Map();\n\n/**\n * Computes a secure cache key for request deduplication.\n * Includes method, full URL, authorization header, and request body.\n *\n * @param options - Processed internal fetch options.\n * @returns Unique string identifier for the request intent.\n */\nexport function computeDedupeKey_(options: InternalFetchOptions_): string {\n const bodyString = typeof options.body === 'string' ? options.body : '';\n const auth = options.headers['authorization'] ?? '';\n return `${options.method} ${options.url} [auth:${auth}] [body:${bodyString}]`;\n}\n\n/**\n * Handles duplicate parallel request coalescing.\n *\n * If an identical request is already in-flight, returns a cloned response of the existing\n * promise to avoid redundant network round-trips.\n *\n * @param options - Processed internal fetch options.\n * @returns A promise resolving to an independent cloned `Response`.\n * @internal\n */\nexport async function handleRemoveDuplicate_(options: InternalFetchOptions_): Promise<Response> {\n if (options.removeDuplicate === 'never') {\n return handleRetryPattern_(options);\n }\n\n DEV_MODE && logger_.logMethod?.('handleRemoveDuplicate_');\n\n const cacheKey = computeDedupeKey_(options);\n\n let requestAsync = duplicateRequestStorage_.get(cacheKey);\n if (requestAsync == null) {\n requestAsync = handleRetryPattern_(options);\n duplicateRequestStorage_.set(cacheKey, requestAsync);\n }\n\n try {\n const response = await requestAsync;\n\n // Clean up stored promise for 'until_load' or failed responses\n if (!response.ok || options.removeDuplicate === 'until_load') {\n duplicateRequestStorage_.delete(cacheKey);\n }\n\n // Return a clone so every concurrent caller can independently consume the body\n return response.clone();\n } catch (err) {\n // If request failed, remove from storage immediately\n duplicateRequestStorage_.delete(cacheKey);\n throw err;\n }\n}\n",
10
+ "import {FetchError} from './error.js';\nimport {handleRemoveDuplicate_} from './dedupe.js';\nimport {logger_} from './options.js';\nimport {delay} from '@alwatr/delay';\n\nimport type {InternalFetchOptions_} from './type.js';\n\n/**\n * Executes the caching lifecycle according to `cacheStrategy`.\n *\n * Interacts safely with Cache API:\n * - Falls back to network when Cache API is unavailable or throws.\n * - Guards against caching non-GET requests.\n * - Clones responses before storing to keep response bodies consumable.\n *\n * @param options - Processed internal fetch options.\n * @returns A promise resolving to a cached or freshly fetched `Response`.\n * @internal\n */\nexport async function handleCacheStrategy_(options: InternalFetchOptions_): Promise<Response> {\n if (options.cacheStrategy === 'network_only') {\n return handleRemoveDuplicate_(options);\n }\n\n DEV_MODE && logger_.logMethod?.('handleCacheStrategy_');\n\n let cacheStorage: Cache;\n try {\n cacheStorage = await caches.open(options.cacheStorageName);\n } catch (err) {\n DEV_MODE && logger_.accident('handleCacheStrategy_', 'cache_open_failed', {err});\n options.cacheStrategy = 'network_only';\n return handleRemoveDuplicate_(options);\n }\n\n const request = new Request(options.url, options);\n\n switch (options.cacheStrategy) {\n case 'cache_first': {\n try {\n const cachedResponse = await cacheStorage.match(request);\n if (cachedResponse != null) {\n return cachedResponse;\n }\n } catch (err) {\n DEV_MODE && logger_.accident('handleCacheStrategy_', 'cache_match_failed', {err});\n }\n\n const response = await handleRemoveDuplicate_(options);\n if (response.ok) {\n try {\n await cacheStorage.put(request, response.clone());\n } catch {\n // ignore cache put failures\n }\n }\n return response;\n }\n\n case 'cache_only': {\n let cachedResponse: Response | undefined;\n try {\n cachedResponse = await cacheStorage.match(request);\n } catch (err) {\n DEV_MODE && logger_.accident('handleCacheStrategy_', 'cache_only_match_failed', {err});\n }\n\n if (cachedResponse == null) {\n throw new FetchError('cache_not_found', 'Resource not found in cache');\n }\n return cachedResponse;\n }\n\n case 'network_first': {\n try {\n const networkResponse = await handleRemoveDuplicate_(options);\n if (networkResponse.ok) {\n try {\n await cacheStorage.put(request, networkResponse.clone());\n } catch {\n // ignore cache put failures\n }\n }\n return networkResponse;\n } catch (err) {\n try {\n const cachedResponse = await cacheStorage.match(request);\n if (cachedResponse != null) {\n return cachedResponse;\n }\n } catch {\n // ignore cache match error and throw original error\n }\n throw err;\n }\n }\n\n case 'update_cache': {\n const networkResponse = await handleRemoveDuplicate_(options);\n if (networkResponse.ok) {\n try {\n await cacheStorage.put(request, networkResponse.clone());\n } catch {\n // ignore cache put failures\n }\n }\n return networkResponse;\n }\n\n case 'stale_while_revalidate': {\n let cachedResponse: Response | undefined;\n try {\n cachedResponse = await cacheStorage.match(request);\n } catch {\n // ignore cache match error\n }\n\n const fetchedResponsePromise = handleRemoveDuplicate_(options).then(async (networkResponse) => {\n if (networkResponse.ok) {\n try {\n await cacheStorage.put(request, networkResponse.clone());\n } catch {\n // ignore cache put failures\n }\n if (typeof options.revalidateCallback === 'function') {\n const callback = options.revalidateCallback;\n const revalidatePayload = networkResponse.clone();\n await delay.nextMacrotask();\n try {\n await callback(revalidatePayload);\n } catch (err) {\n DEV_MODE && logger_.accident('handleCacheStrategy_', 'revalidate_callback_failed', {err});\n }\n }\n }\n return networkResponse;\n });\n\n return cachedResponse ?? fetchedResponsePromise;\n }\n\n default: {\n return handleRemoveDuplicate_(options);\n }\n }\n}\n",
11
+ "import {FetchError, httpStatusToErrorReason} from './error.js';\nimport {handleCacheStrategy_} from './cache.js';\nimport {processOptions_, logger_} from './options.js';\n\nimport type {FetchJsonOptions, FetchJsonResponse, FetchOptions, FetchResponse} from './type.js';\n\n/**\n * An enhanced wrapper for the native `fetch` function.\n *\n * Provides:\n * - **Deterministic Errors**: Semantic `FetchError` reasons (e.g. `unauthorized`, `forbidden`, `not_found`, `server_error`, `timeout`, `aborted`, `rate_limited`).\n * - **Go-Style Tuple Return**: Never throws, returns `[response, null]` on success or `[null, FetchError]` on failure.\n * - **Automatic Timeout**: Aborts the request if it exceeds `timeout` duration.\n * - **Configurable Retry**: Automatically retries transient 5xx, 429, 408, or network errors with `retryDelay` and `Retry-After` support.\n * - **Parallel Deduplication**: Collapses identical concurrent in-flight requests.\n * - **Cache Strategies**: Integrates with Cache API (`cache_first`, `stale_while_revalidate`, etc.).\n * - **Isolated Headers & Query Params**: Safely formats query parameters and authorization credentials without mutating caller objects.\n *\n * @param url - The URL to fetch.\n * @param options - Configuration options for the fetch request.\n * @returns A promise resolving to `[Response, null]` on success, or `[null, FetchError]` on failure.\n *\n * @example\n * ```typescript\n * import {fetch} from '@alwatr/fetch';\n *\n * const [response, error] = await fetch('/api/products', {\n * queryParams: { limit: 10 },\n * timeout: '5s',\n * });\n *\n * if (error) {\n * if (error.reason === 'not_found') {\n * console.warn('Product not found');\n * }\n * return;\n * }\n *\n * const data = await response.json();\n * ```\n */\nexport async function fetch(url: string, options: FetchOptions = {}): Promise<FetchResponse> {\n const options_ = processOptions_(url, options);\n DEV_MODE && logger_.logMethodArgs?.('fetch', options_);\n\n try {\n const response = await handleCacheStrategy_(options_);\n\n if (!response.ok) {\n const reason = httpStatusToErrorReason(response.status);\n throw new FetchError(reason, `HTTP error! status: ${response.status} ${response.statusText}`, response);\n }\n\n return [response, null];\n } catch (err) {\n let error: FetchError;\n\n if (err instanceof FetchError) {\n error = err;\n\n if (error.response != null && error.data == null) {\n const bodyText = await error.response.text().catch(() => '');\n\n if (bodyText.trim().length > 0) {\n try {\n error.data = JSON.parse(bodyText);\n } catch {\n error.data = bodyText;\n }\n }\n }\n } else if (err instanceof Error) {\n if (err.name === 'AbortError') {\n error = new FetchError('aborted', err.message);\n } else {\n error = new FetchError('network_error', err.message);\n }\n } else {\n error = new FetchError('unknown_error', String(err ?? 'unknown_error'));\n }\n\n DEV_MODE && logger_.accident('fetch', error.reason, {error});\n return [null, error];\n }\n}\n\n/**\n * An enhanced wrapper for `fetch` that automatically parses JSON responses.\n *\n * Accepts unconstrained generic interfaces, DTOs, and arrays without requiring index signatures.\n *\n * @template T - The expected type of the JSON response payload.\n *\n * @param url - The URL to fetch.\n * @param options - Configuration options for the fetch request.\n * @returns A promise resolving to `[data, null]` where data is typed as `T`, or `[null, FetchError]`.\n *\n * @example\n * ```typescript\n * import {fetchJson} from '@alwatr/fetch';\n *\n * interface User {\n * id: string;\n * name: string;\n * }\n *\n * const [users, error] = await fetchJson<User[]>('/api/users');\n * if (error) {\n * console.error('Failed to load users:', error.reason);\n * return;\n * }\n * console.log('Users count:', users.length);\n * ```\n */\nexport async function fetchJson<T = unknown>(\n url: string,\n options: FetchJsonOptions = {},\n): Promise<FetchJsonResponse<T>> {\n DEV_MODE && logger_.logMethod?.('fetchJson');\n\n const [response, error] = await fetch(url, options);\n\n if (error) {\n return [null, error];\n }\n\n const bodyText = await response.text().catch(() => '');\n if (bodyText.trim().length === 0) {\n const parseError = new FetchError(\n 'json_parse_error',\n 'Response body is empty, cannot parse JSON',\n response,\n bodyText,\n );\n DEV_MODE && logger_.accident('fetchJson', parseError.reason, {error: parseError});\n return [null, parseError];\n }\n\n try {\n const data = JSON.parse(bodyText) as T;\n\n if (\n options.requireJsonResponseWithOkTrue\n && (typeof data !== 'object' || data === null || (data as Record<string, unknown>).ok !== true)\n ) {\n const parseError = new FetchError(\n 'json_response_error',\n 'Response JSON \"ok\" property is not true',\n response,\n data,\n );\n DEV_MODE && logger_.accident('fetchJson', parseError.reason, {error: parseError});\n return [null, parseError];\n }\n\n return [data, null];\n } catch (err) {\n const parseError = new FetchError(\n 'json_parse_error',\n err instanceof Error ? err.message : 'Failed to parse JSON response',\n response,\n bodyText,\n );\n DEV_MODE && logger_.accident('fetchJson', parseError.reason, {error: parseError});\n return [null, parseError];\n }\n}\n\nfetchJson.version = fetch.version = __package_version__;\n"
8
12
  ],
9
- "mappings": "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",
10
- "debugId": "A246457AD014A4A964756E2164756E21",
13
+ "mappings": "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",
14
+ "debugId": "CB669A3FF161DEFF64756E2164756E21",
11
15
  "names": []
12
16
  }
@@ -0,0 +1,40 @@
1
+ import type { AlwatrFetchOptions_, FetchOptions, InternalFetchOptions_, QueryParams } from './type.js';
2
+ export declare const logger_: import("@alwatr/logger").AlwatrLogger;
3
+ export declare const globalThis_: typeof globalThis;
4
+ /**
5
+ * Immutable default options for all fetch requests.
6
+ */
7
+ export declare const defaultFetchOptions: Readonly<AlwatrFetchOptions_>;
8
+ /**
9
+ * Normalizes any standard `HeadersInit` into a fresh, isolated lowercase string record.
10
+ *
11
+ * @param headers - User-provided headers (plain object, Headers instance, or entries array).
12
+ * @param baseHeaders - Optional base headers to merge with the user-provided headers.
13
+ * @returns An isolated `Record<string, string>`.
14
+ */
15
+ export declare function normalizeHeaders_(headers?: HeadersInit, baseHeaders?: Record<string, string>): Record<string, string>;
16
+ /**
17
+ * Serializes query parameters into a query string.
18
+ *
19
+ * @param queryParams - Dictionary of query parameters.
20
+ * @returns Serialized URL query string (without leading `?` or `&`).
21
+ */
22
+ export declare function serializeQueryParams_(queryParams: QueryParams): string;
23
+ /**
24
+ * Appends query parameters to a URL, correctly respecting existing query parameters and hash anchors.
25
+ *
26
+ * @param url - The target URL.
27
+ * @param queryParams - Query parameters to append.
28
+ * @returns The resulting URL string.
29
+ */
30
+ export declare function appendQueryParams_(url: string, queryParams?: QueryParams): string;
31
+ /**
32
+ * Processes, sanitizes, and normalizes user-provided fetch options into a complete, isolated options object.
33
+ *
34
+ * @param url - The target URL.
35
+ * @param options - User-provided options.
36
+ * @returns Internal, complete, and isolated fetch options.
37
+ * @internal
38
+ */
39
+ export declare function processOptions_(url: string, options?: FetchOptions): InternalFetchOptions_;
40
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,mBAAmB,EAAE,YAAY,EAAE,qBAAqB,EAAE,WAAW,EAAC,MAAM,WAAW,CAAC;AAErG,eAAO,MAAM,OAAO,uCAAgC,CAAC;AAErD,eAAO,MAAM,WAAW,mBAAkB,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,mBAAmB,CAS7D,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,CAAC,EAAE,WAAW,EACrB,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACvC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA+BxB;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,CAqBtE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,MAAM,CAsBjF;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,qBAAqB,CAsD9F"}
@@ -0,0 +1,26 @@
1
+ import type { InternalFetchOptions_ } from './type.js';
2
+ /**
3
+ * Checks whether an HTTP response status code is retryable.
4
+ *
5
+ * Retryable statuses:
6
+ * - Any 5xx Server Error (500, 502, 503, 504, ...)
7
+ * - 408 Request Timeout
8
+ * - 429 Too Many Requests
9
+ */
10
+ export declare function isRetryableStatus_(status: number): boolean;
11
+ /**
12
+ * Parses the `Retry-After` header value (in seconds or HTTP-date) if present.
13
+ *
14
+ * @param response - The HTTP Response object.
15
+ * @returns Delay duration in milliseconds, or undefined if absent/invalid.
16
+ */
17
+ export declare function parseRetryAfterHeader_(response?: Response): number | undefined;
18
+ /**
19
+ * Executes a fetch request with automatic retries on transient errors (5xx, 429, 408, network failures, timeouts).
20
+ *
21
+ * @param options - Processed internal fetch options.
22
+ * @returns A promise resolving to the final `Response` after retry cycles.
23
+ * @internal
24
+ */
25
+ export declare function handleRetryPattern_(options: InternalFetchOptions_): Promise<Response>;
26
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../src/retry.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,WAAW,CAAC;AAIrD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAM1D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAgB9E;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+C3F"}
@@ -0,0 +1,13 @@
1
+ import type { InternalFetchOptions_ } from './type.js';
2
+ /**
3
+ * Executes a native `fetch` wrapped with an `AbortController` timeout.
4
+ *
5
+ * Checks for pre-aborted external signals, respects external cancellation,
6
+ * and guarantees listener and timer cleanup on completion.
7
+ *
8
+ * @param options - Processed internal fetch options.
9
+ * @returns A promise resolving to the native `Response` or rejecting with `FetchError`.
10
+ * @internal
11
+ */
12
+ export declare function handleTimeout_(options: InternalFetchOptions_): Promise<Response>;
13
+ //# sourceMappingURL=timeout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../src/timeout.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,WAAW,CAAC;AAIrD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkEhF"}
package/dist/type.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- import type { DictionaryOpt, DictionaryReq, JsonValue } from '@alwatr/type-helper';
1
+ import type { DictionaryOpt, JsonValue } from '@alwatr/type-helper';
2
2
  import type { FetchError } from './error.js';
3
3
  import type { HttpMethod, HttpRequestHeaders } from '@alwatr/http-primer';
4
4
  import type { Duration } from '@alwatr/parse-duration';
5
5
  /**
6
6
  * A dictionary of query parameters.
7
- * Keys are strings, and values can be strings, numbers, or booleans.
7
+ * Keys are strings, and values can be strings, numbers, booleans, or arrays of these primitives.
8
8
  */
9
- export type QueryParams = DictionaryOpt<string | number | boolean>;
9
+ export type QueryParams = DictionaryOpt<string | number | boolean | readonly (string | number | boolean)[] | (string | number | boolean)[]>;
10
10
  /**
11
11
  * Defines the caching strategy for a fetch request.
12
12
  *
@@ -36,9 +36,9 @@ export interface AlwatrFetchOptions_ {
36
36
  */
37
37
  method: HttpMethod;
38
38
  /**
39
- * An object of request headers.
39
+ * Request headers. Supports plain object, Web Standard `Headers`, or entries array.
40
40
  */
41
- headers: HttpRequestHeaders & DictionaryReq<string>;
41
+ headers?: HttpRequestHeaders | HeadersInit;
42
42
  /**
43
43
  * Request timeout duration. Can be a number (milliseconds) or a string (e.g., '5s').
44
44
  * Set to `0` to disable.
@@ -47,29 +47,29 @@ export interface AlwatrFetchOptions_ {
47
47
  timeout: Duration;
48
48
  /**
49
49
  * Number of times to retry a failed request.
50
- * Retries occur on network errors, timeouts, or 5xx server responses.
50
+ * Retries occur on network errors, timeouts, 408/429 status codes, or 5xx server responses.
51
51
  * @default 3
52
52
  */
53
53
  retry: number;
54
54
  /**
55
- * Delay before each retry attempt. Can be a number (milliseconds) or a string (e.g., '2s').
55
+ * Delay before each retry attempt. Can be a number (milliseconds) or a string (e.g., '1s').
56
56
  * @default '1s'
57
57
  */
58
58
  retryDelay: Duration;
59
59
  /**
60
60
  * Strategy for handling duplicate parallel requests.
61
- * Uniqueness is determined by method, URL, and request body.
61
+ * Uniqueness is determined by method, URL, query parameters, request body, and authorization context.
62
62
  * @default 'never'
63
63
  */
64
64
  removeDuplicate: CacheDuplicate;
65
65
  /**
66
66
  * The caching strategy to use for the request.
67
- * Requires a browser environment with Cache API support.
67
+ * Requires a browser or environment with Cache API support.
68
68
  * @default 'network_only'
69
69
  */
70
70
  cacheStrategy: CacheStrategy;
71
71
  /**
72
- * A callback function that is executed with the fresh response when using the 'stale_while_revalidate' cache strategy.
72
+ * A callback function executed with the fresh response when using 'stale_while_revalidate'.
73
73
  */
74
74
  revalidateCallback?: (response: Response) => void | Promise<void>;
75
75
  /**
@@ -78,7 +78,7 @@ export interface AlwatrFetchOptions_ {
78
78
  */
79
79
  cacheStorageName: string;
80
80
  /**
81
- * A JavaScript object to be sent as the request's JSON body.
81
+ * A JavaScript value to be serialized as the request's JSON body.
82
82
  * Automatically sets the 'Content-Type' header to 'application/json'.
83
83
  */
84
84
  bodyJson?: JsonValue;
@@ -89,37 +89,76 @@ export interface AlwatrFetchOptions_ {
89
89
  /**
90
90
  * A bearer token to be added to the 'Authorization' header.
91
91
  */
92
- bearerToken?: string;
92
+ bearerToken?: string | null;
93
93
  /**
94
94
  * Alwatr-specific authentication credentials.
95
95
  */
96
96
  alwatrAuth?: {
97
97
  userId: string;
98
98
  userToken: string;
99
- };
99
+ } | null;
100
100
  }
101
101
  /**
102
102
  * Combined type for fetch options, including standard RequestInit properties.
103
103
  */
104
104
  export type FetchOptions = Partial<AlwatrFetchOptions_> & Omit<RequestInit, 'headers'>;
105
+ /**
106
+ * Options for `fetchJson`, extending `FetchOptions` with JSON-specific flags.
107
+ */
105
108
  export type FetchJsonOptions = FetchOptions & {
109
+ /**
110
+ * If `true`, requires the parsed JSON body to have an `ok: true` property.
111
+ * If `ok` is missing or not `true`, fails with `json_response_error`.
112
+ */
106
113
  requireJsonResponseWithOkTrue?: true;
107
114
  };
108
115
  /**
109
- * Represents the tuple returned by the fetch function.
110
- * On success, it's `[Response, null]`. On failure, it's `[null, FetchError]`.
116
+ * Represents the tuple returned by the `fetch` function.
117
+ * On success: `[Response, null]`. On failure: `[null, FetchError]`.
111
118
  */
112
- export type FetchResponse = Promise<[Response, null] | [null, FetchError]>;
119
+ export type FetchResponse = readonly [Response, null] | readonly [null, FetchError];
120
+ /**
121
+ * Represents the tuple returned by `fetchJson`.
122
+ * On success: `[T, null]`. On failure: `[null, FetchError]`.
123
+ */
124
+ export type FetchJsonResponse<T = unknown> = readonly [T, null] | readonly [null, FetchError];
113
125
  /**
114
126
  * Defines the specific reason for a fetch failure.
115
- * - `http_error`: An HTTP error status was received (e.g., 404, 500).
116
- * - `timeout`: The request was aborted due to a timeout.
117
- * - `cache_not_found`: The requested resource was not found in the cache_only strategy.
118
- * - `network_error`: A generic network-level error occurred.
119
- * - `aborted`: The request was aborted by a user-provided signal.
120
- * - `json_parse_error`: The response body could not be parsed as JSON.
121
- * - `json_response_error`: The response JSON "ok" property is not true.
122
- * - `unknown_error`: An unspecified error occurred.
127
+ *
128
+ * Semantic HTTP Client Errors (4xx):
129
+ * - `bad_request`: 400 Bad Request
130
+ * - `unauthorized`: 401 Unauthorized
131
+ * - `forbidden`: 403 Forbidden
132
+ * - `not_found`: 404 Not Found
133
+ * - `request_timeout`: 408 Request Timeout
134
+ * - `conflict`: 409 Conflict
135
+ * - `payload_too_large`: 413 Payload Too Large
136
+ * - `unprocessable_content`: 422 Unprocessable Entity / Content
137
+ * - `rate_limited`: 429 Too Many Requests
138
+ * - `http_error`: Other 4xx client errors
139
+ *
140
+ * Semantic HTTP Server Errors (5xx):
141
+ * - `server_error`: Any 5xx server-side error (500, 502, 503, 504, etc.)
142
+ *
143
+ * Network & Lifecycle Errors:
144
+ * - `timeout`: The request exceeded the configured timeout duration.
145
+ * - `aborted`: The request was cancelled by an AbortSignal.
146
+ * - `network_error`: A network-level failure occurred (DNS, connection reset, offline).
147
+ * - `cache_not_found`: Resource was not found when using `cache_only`.
148
+ * - `json_parse_error`: Response body could not be parsed as valid JSON.
149
+ * - `json_response_error`: Response JSON `ok` property was not true when `requireJsonResponseWithOkTrue` was set.
150
+ * - `unknown_error`: An unexpected or untyped error occurred.
151
+ */
152
+ export type FetchErrorReason = 'bad_request' | 'unauthorized' | 'forbidden' | 'not_found' | 'request_timeout' | 'conflict' | 'payload_too_large' | 'unprocessable_content' | 'rate_limited' | 'http_error' | 'server_error' | 'timeout' | 'aborted' | 'network_error' | 'cache_not_found' | 'json_parse_error' | 'json_response_error' | 'unknown_error';
153
+ /**
154
+ * Internal-only normalized fetch options type.
155
+ * @internal
123
156
  */
124
- export type FetchErrorReason = 'http_error' | 'cache_not_found' | 'timeout' | 'network_error' | 'aborted' | 'json_parse_error' | 'json_response_error' | 'unknown_error';
157
+ export interface InternalFetchOptions_ extends Omit<AlwatrFetchOptions_, 'headers' | 'method' | 'timeout' | 'retryDelay'>, Omit<RequestInit, 'headers' | 'method'> {
158
+ url: string;
159
+ method: HttpMethod;
160
+ headers: HttpRequestHeaders;
161
+ timeout: number;
162
+ retryDelay: number;
163
+ }
125
164
  //# sourceMappingURL=type.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAE,SAAS,EAAC,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAC,UAAU,EAAE,kBAAkB,EAAC,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,wBAAwB,CAAC;AAErD;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,aAAa,CAAC,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GACrB,cAAc,GACd,eAAe,GACf,YAAY,GACZ,aAAa,GACb,cAAc,GACd,wBAAwB,CAAC;AAE7B;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,MAAM,EAAE,UAAU,CAAC;IAEnB;;OAEG;IACH,OAAO,EAAE,kBAAkB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAEpD;;;;OAIG;IACH,OAAO,EAAE,QAAQ,CAAC;IAElB;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,UAAU,EAAE,QAAQ,CAAC;IAErB;;;;OAIG;IACH,eAAe,EAAE,cAAc,CAAC;IAEhC;;;;OAIG;IACH,aAAa,EAAE,aAAa,CAAC;IAE7B;;OAEG;IACH,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAElE;;;OAGG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,UAAU,CAAC,EAAE;QACX,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,mBAAmB,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAEvF,MAAM,MAAM,gBAAgB,GAAG,YAAY,GAAG;IAAC,6BAA6B,CAAC,EAAE,IAAI,CAAA;CAAC,CAAC;AAErF;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;AAE3E;;;;;;;;;;GAUG;AACH,MAAM,MAAM,gBAAgB,GACxB,YAAY,GACZ,iBAAiB,GACjB,SAAS,GACT,eAAe,GACf,SAAS,GACT,kBAAkB,GAClB,qBAAqB,GACrB,eAAe,CAAC"}
1
+ {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alwatr/fetch",
3
- "version": "10.0.3",
3
+ "version": "10.1.1",
4
4
  "description": "`@alwatr/fetch` is an enhanced, lightweight, and dependency-free wrapper for the native `fetch` API. It provides modern features like caching strategies, request retries, timeouts, and intelligent duplicate request handling, all in a compact package.",
5
5
  "license": "MPL-2.0",
6
6
  "author": "S. Ali Mihandoost <ali.mihandoost@gmail.com> (https://ali.mihandoost.com)",
@@ -22,11 +22,10 @@
22
22
  },
23
23
  "sideEffects": false,
24
24
  "dependencies": {
25
- "@alwatr/delay": "10.0.0",
26
- "@alwatr/global-this": "10.0.0",
27
- "@alwatr/has-own": "10.0.0",
25
+ "@alwatr/delay": "10.1.0",
26
+ "@alwatr/global-this": "10.1.0",
28
27
  "@alwatr/http-primer": "10.0.0",
29
- "@alwatr/logger": "10.0.0",
28
+ "@alwatr/logger": "10.1.0",
30
29
  "@alwatr/parse-duration": "10.0.0"
31
30
  },
32
31
  "devDependencies": {
@@ -85,5 +84,5 @@
85
84
  "utility",
86
85
  "utils"
87
86
  ],
88
- "gitHead": "b2eede4682c20480113f1771941e2954d1cc260e"
87
+ "gitHead": "7e2e248f48b2b6ce8b9a71efdf8eb65de52697df"
89
88
  }