@alwatr/fetch 7.1.2 → 7.1.3
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/CHANGELOG.md +4 -0
- package/dist/main.cjs +2 -2
- package/dist/main.mjs +2 -2
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [7.1.3](https://github.com/Alwatr/nanolib/compare/@alwatr/fetch@7.1.2...@alwatr/fetch@7.1.3) (2025-12-23)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @alwatr/fetch
|
|
9
|
+
|
|
6
10
|
## [7.1.2](https://github.com/Alwatr/nanolib/compare/@alwatr/fetch@7.1.1...@alwatr/fetch@7.1.2) (2025-12-13)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @alwatr/fetch
|
package/dist/main.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** 📦 @alwatr/fetch v7.1.
|
|
2
|
-
__dev_mode__: console.debug("📦 @alwatr/fetch v7.1.
|
|
1
|
+
/** 📦 @alwatr/fetch v7.1.3 */
|
|
2
|
+
__dev_mode__: console.debug("📦 @alwatr/fetch v7.1.3");
|
|
3
3
|
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;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 main_exports={};__export(main_exports,{FetchError:()=>FetchError,cacheSupported:()=>cacheSupported,fetch:()=>fetch,fetchJson:()=>fetchJson});module.exports=__toCommonJS(main_exports);var import_delay=require("@alwatr/delay");var import_global_this=require("@alwatr/global-this");var import_has_own=require("@alwatr/has-own");var import_http_primer=require("@alwatr/http-primer");var import_logger=require("@alwatr/logger");var import_parse_duration=require("@alwatr/parse-duration");var FetchError=class extends Error{constructor(reason,message,response,data){super(message);this.name="FetchError";this.reason=reason;this.response=response;this.data=data}};var logger_=(0,import_logger.createLogger)("@alwatr/fetch");var globalThis_=(0,import_global_this.getGlobalThis)();var cacheSupported=(0,import_has_own.hasOwn)(globalThis_,"caches");var duplicateRequestStorage_={};var defaultFetchOptions={method:"GET",headers:{},timeout:8e3,retry:3,retryDelay:1e3,removeDuplicate:"never",cacheStrategy:"network_only",cacheStorageName:"fetch_cache"};function _processOptions(url,options){logger_.logMethodArgs?.("_processOptions",{url,options});const options_={...defaultFetchOptions,...options,url};options_.window??=null;if(options_.removeDuplicate==="auto"){options_.removeDuplicate=cacheSupported?"until_load":"always"}if(options_.url.lastIndexOf("?")===-1&&options_.queryParams!=null){const queryParams=options_.queryParams;const queryArray=Object.keys(queryParams).map(key=>`${encodeURIComponent(key)}=${encodeURIComponent(String(queryParams[key]))}`);if(queryArray.length>0){options_.url+="?"+queryArray.join("&")}}if(options_.bodyJson!==void 0){options_.body=JSON.stringify(options_.bodyJson);options_.headers["content-type"]=import_http_primer.MimeTypes.JSON}if(options_.bearerToken!==void 0){options_.headers.authorization=`Bearer ${options_.bearerToken}`}else if(options_.alwatrAuth!==void 0){options_.headers.authorization=`Alwatr ${options_.alwatrAuth.userId}:${options_.alwatrAuth.userToken}`}logger_.logProperty?.("fetch.options",options_);return options_}async function handleCacheStrategy_(options){if(options.cacheStrategy==="network_only"){return handleRemoveDuplicate_(options)}logger_.logMethod?.("handleCacheStrategy_");if(!cacheSupported){logger_.incident?.("fetch","fetch_cache_strategy_unsupported",{cacheSupported});options.cacheStrategy="network_only";return handleRemoveDuplicate_(options)}const cacheStorage=await caches.open(options.cacheStorageName);const request=new Request(options.url,options);switch(options.cacheStrategy){case"cache_first":{const cachedResponse=await cacheStorage.match(request);if(cachedResponse!=null){return cachedResponse}const response=await handleRemoveDuplicate_(options);if(response.ok){cacheStorage.put(request,response.clone())}return response}case"cache_only":{const cachedResponse=await cacheStorage.match(request);if(cachedResponse==null){throw new FetchError("cache_not_found","Resource not found in cache")}return cachedResponse}case"network_first":{try{const networkResponse=await handleRemoveDuplicate_(options);if(networkResponse.ok){cacheStorage.put(request,networkResponse.clone())}return networkResponse}catch(err){const cachedResponse=await cacheStorage.match(request);if(cachedResponse!=null){return cachedResponse}throw err}}case"update_cache":{const networkResponse=await handleRemoveDuplicate_(options);if(networkResponse.ok){cacheStorage.put(request,networkResponse.clone())}return networkResponse}case"stale_while_revalidate":{const cachedResponse=await cacheStorage.match(request);const fetchedResponsePromise=handleRemoveDuplicate_(options).then(networkResponse=>{if(networkResponse.ok){cacheStorage.put(request,networkResponse.clone());if(typeof options.revalidateCallback==="function"){setTimeout(options.revalidateCallback,0,networkResponse.clone())}}return networkResponse});return cachedResponse??fetchedResponsePromise}default:{return handleRemoveDuplicate_(options)}}}async function handleRemoveDuplicate_(options){if(options.removeDuplicate==="never"){return handleRetryPattern_(options)}logger_.logMethod?.("handleRemoveDuplicate_");const bodyString=typeof options.body==="string"?options.body:"";const cacheKey=`${options.method} ${options.url} ${bodyString}`;duplicateRequestStorage_[cacheKey]??=handleRetryPattern_(options);try{const response=await duplicateRequestStorage_[cacheKey];if(duplicateRequestStorage_[cacheKey]!=null){if(response.ok!==true||options.removeDuplicate==="until_load"){delete duplicateRequestStorage_[cacheKey]}}return response.clone()}catch(err){delete duplicateRequestStorage_[cacheKey];throw err}}async function handleRetryPattern_(options){if(!(options.retry>1)){return handleTimeout_(options)}logger_.logMethod?.("handleRetryPattern_");options.retry--;const externalAbortSignal=options.signal;try{const response=await handleTimeout_(options);if(!response.ok&&response.status>=import_http_primer.HttpStatusCodes.Error_Server_500_Internal_Server_Error){throw new FetchError("http_error",`HTTP error! status: ${response.status} ${response.statusText}`,response)}return response}catch(err){logger_.accident("fetch","fetch_failed_retry",err);if(globalThis_.navigator?.onLine===false){logger_.accident("handleRetryPattern_","offline","Skip retry because offline");throw err}await import_delay.delay.by(options.retryDelay);options.signal=externalAbortSignal;return handleRetryPattern_(options)}}function handleTimeout_(options){if(options.timeout===0){return globalThis_.fetch(options.url,options)}logger_.logMethod?.("handleTimeout_");return new Promise((resolved,reject)=>{const abortController=typeof AbortController==="function"?new AbortController:null;const externalAbortSignal=options.signal;options.signal=abortController?.signal;if(abortController!==null&&externalAbortSignal!=null){externalAbortSignal.addEventListener("abort",()=>abortController.abort(),{once:true})}const timeoutId=setTimeout(()=>{reject(new FetchError("timeout","fetch_timeout"));abortController?.abort("fetch_timeout")},(0,import_parse_duration.parseDuration)(options.timeout));globalThis_.fetch(options.url,options).then(response=>resolved(response)).catch(reason=>reject(reason)).finally(()=>{clearTimeout(timeoutId)})})}async function fetch(url,options={}){logger_.logMethodArgs?.("fetch",{url,options});const options_=_processOptions(url,options);try{const response=await handleCacheStrategy_(options_);if(!response.ok){throw new FetchError("http_error",`HTTP error! status: ${response.status} ${response.statusText}`,response)}return[response,null]}catch(err){let error;if(err instanceof FetchError){error=err;if(error.response!==void 0&&error.data===void 0){const bodyText=await error.response.text().catch(()=>"");if(bodyText.trim().length>0){try{error.data=JSON.parse(bodyText)}catch{error.data=bodyText}}}}else if(err instanceof Error){if(err.name==="AbortError"){error=new FetchError("aborted",err.message)}else{error=new FetchError("network_error",err.message)}}else{error=new FetchError("unknown_error",String(err??"unknown_error"))}logger_.error("fetch",error.reason,{error});return[null,error]}}async function fetchJson(url,options={}){logger_.logMethodArgs?.("fetchJson",{url,options});const[response,error]=await fetch(url,options);if(error){return[null,error]}const bodyText=await response.text().catch(()=>"");if(bodyText.trim().length===0){const parseError=new FetchError("json_parse_error","Response body is empty, cannot parse JSON",response,bodyText);logger_.error("fetchJson",parseError.reason,{error:parseError});return[null,parseError]}try{const data=JSON.parse(bodyText);if(options.requireJsonResponseWithOkTrue&&data.ok!==true){const parseError=new FetchError("json_response_error",'Response JSON "ok" property is not true',response,data);logger_.error("fetchJson",parseError.reason,{error:parseError});return[null,parseError]}return[data,null]}catch(err){const parseError=new FetchError("json_parse_error",err instanceof Error?err.message:"Failed to parse JSON response",response,bodyText);logger_.error("fetchJson",parseError.reason,{error:parseError});return[null,parseError]}}0&&(module.exports={FetchError,cacheSupported,fetch,fetchJson});
|
|
4
4
|
//# sourceMappingURL=main.cjs.map
|
package/dist/main.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** 📦 @alwatr/fetch v7.1.
|
|
2
|
-
__dev_mode__: console.debug("📦 @alwatr/fetch v7.1.
|
|
1
|
+
/** 📦 @alwatr/fetch v7.1.3 */
|
|
2
|
+
__dev_mode__: console.debug("📦 @alwatr/fetch v7.1.3");
|
|
3
3
|
import{delay}from"@alwatr/delay";import{getGlobalThis}from"@alwatr/global-this";import{hasOwn}from"@alwatr/has-own";import{HttpStatusCodes,MimeTypes}from"@alwatr/http-primer";import{createLogger}from"@alwatr/logger";import{parseDuration}from"@alwatr/parse-duration";var FetchError=class extends Error{constructor(reason,message,response,data){super(message);this.name="FetchError";this.reason=reason;this.response=response;this.data=data}};var logger_=createLogger("@alwatr/fetch");var globalThis_=getGlobalThis();var cacheSupported=hasOwn(globalThis_,"caches");var duplicateRequestStorage_={};var defaultFetchOptions={method:"GET",headers:{},timeout:8e3,retry:3,retryDelay:1e3,removeDuplicate:"never",cacheStrategy:"network_only",cacheStorageName:"fetch_cache"};function _processOptions(url,options){logger_.logMethodArgs?.("_processOptions",{url,options});const options_={...defaultFetchOptions,...options,url};options_.window??=null;if(options_.removeDuplicate==="auto"){options_.removeDuplicate=cacheSupported?"until_load":"always"}if(options_.url.lastIndexOf("?")===-1&&options_.queryParams!=null){const queryParams=options_.queryParams;const queryArray=Object.keys(queryParams).map(key=>`${encodeURIComponent(key)}=${encodeURIComponent(String(queryParams[key]))}`);if(queryArray.length>0){options_.url+="?"+queryArray.join("&")}}if(options_.bodyJson!==void 0){options_.body=JSON.stringify(options_.bodyJson);options_.headers["content-type"]=MimeTypes.JSON}if(options_.bearerToken!==void 0){options_.headers.authorization=`Bearer ${options_.bearerToken}`}else if(options_.alwatrAuth!==void 0){options_.headers.authorization=`Alwatr ${options_.alwatrAuth.userId}:${options_.alwatrAuth.userToken}`}logger_.logProperty?.("fetch.options",options_);return options_}async function handleCacheStrategy_(options){if(options.cacheStrategy==="network_only"){return handleRemoveDuplicate_(options)}logger_.logMethod?.("handleCacheStrategy_");if(!cacheSupported){logger_.incident?.("fetch","fetch_cache_strategy_unsupported",{cacheSupported});options.cacheStrategy="network_only";return handleRemoveDuplicate_(options)}const cacheStorage=await caches.open(options.cacheStorageName);const request=new Request(options.url,options);switch(options.cacheStrategy){case"cache_first":{const cachedResponse=await cacheStorage.match(request);if(cachedResponse!=null){return cachedResponse}const response=await handleRemoveDuplicate_(options);if(response.ok){cacheStorage.put(request,response.clone())}return response}case"cache_only":{const cachedResponse=await cacheStorage.match(request);if(cachedResponse==null){throw new FetchError("cache_not_found","Resource not found in cache")}return cachedResponse}case"network_first":{try{const networkResponse=await handleRemoveDuplicate_(options);if(networkResponse.ok){cacheStorage.put(request,networkResponse.clone())}return networkResponse}catch(err){const cachedResponse=await cacheStorage.match(request);if(cachedResponse!=null){return cachedResponse}throw err}}case"update_cache":{const networkResponse=await handleRemoveDuplicate_(options);if(networkResponse.ok){cacheStorage.put(request,networkResponse.clone())}return networkResponse}case"stale_while_revalidate":{const cachedResponse=await cacheStorage.match(request);const fetchedResponsePromise=handleRemoveDuplicate_(options).then(networkResponse=>{if(networkResponse.ok){cacheStorage.put(request,networkResponse.clone());if(typeof options.revalidateCallback==="function"){setTimeout(options.revalidateCallback,0,networkResponse.clone())}}return networkResponse});return cachedResponse??fetchedResponsePromise}default:{return handleRemoveDuplicate_(options)}}}async function handleRemoveDuplicate_(options){if(options.removeDuplicate==="never"){return handleRetryPattern_(options)}logger_.logMethod?.("handleRemoveDuplicate_");const bodyString=typeof options.body==="string"?options.body:"";const cacheKey=`${options.method} ${options.url} ${bodyString}`;duplicateRequestStorage_[cacheKey]??=handleRetryPattern_(options);try{const response=await duplicateRequestStorage_[cacheKey];if(duplicateRequestStorage_[cacheKey]!=null){if(response.ok!==true||options.removeDuplicate==="until_load"){delete duplicateRequestStorage_[cacheKey]}}return response.clone()}catch(err){delete duplicateRequestStorage_[cacheKey];throw err}}async function handleRetryPattern_(options){if(!(options.retry>1)){return handleTimeout_(options)}logger_.logMethod?.("handleRetryPattern_");options.retry--;const externalAbortSignal=options.signal;try{const response=await handleTimeout_(options);if(!response.ok&&response.status>=HttpStatusCodes.Error_Server_500_Internal_Server_Error){throw new FetchError("http_error",`HTTP error! status: ${response.status} ${response.statusText}`,response)}return response}catch(err){logger_.accident("fetch","fetch_failed_retry",err);if(globalThis_.navigator?.onLine===false){logger_.accident("handleRetryPattern_","offline","Skip retry because offline");throw err}await delay.by(options.retryDelay);options.signal=externalAbortSignal;return handleRetryPattern_(options)}}function handleTimeout_(options){if(options.timeout===0){return globalThis_.fetch(options.url,options)}logger_.logMethod?.("handleTimeout_");return new Promise((resolved,reject)=>{const abortController=typeof AbortController==="function"?new AbortController:null;const externalAbortSignal=options.signal;options.signal=abortController?.signal;if(abortController!==null&&externalAbortSignal!=null){externalAbortSignal.addEventListener("abort",()=>abortController.abort(),{once:true})}const timeoutId=setTimeout(()=>{reject(new FetchError("timeout","fetch_timeout"));abortController?.abort("fetch_timeout")},parseDuration(options.timeout));globalThis_.fetch(options.url,options).then(response=>resolved(response)).catch(reason=>reject(reason)).finally(()=>{clearTimeout(timeoutId)})})}async function fetch(url,options={}){logger_.logMethodArgs?.("fetch",{url,options});const options_=_processOptions(url,options);try{const response=await handleCacheStrategy_(options_);if(!response.ok){throw new FetchError("http_error",`HTTP error! status: ${response.status} ${response.statusText}`,response)}return[response,null]}catch(err){let error;if(err instanceof FetchError){error=err;if(error.response!==void 0&&error.data===void 0){const bodyText=await error.response.text().catch(()=>"");if(bodyText.trim().length>0){try{error.data=JSON.parse(bodyText)}catch{error.data=bodyText}}}}else if(err instanceof Error){if(err.name==="AbortError"){error=new FetchError("aborted",err.message)}else{error=new FetchError("network_error",err.message)}}else{error=new FetchError("unknown_error",String(err??"unknown_error"))}logger_.error("fetch",error.reason,{error});return[null,error]}}async function fetchJson(url,options={}){logger_.logMethodArgs?.("fetchJson",{url,options});const[response,error]=await fetch(url,options);if(error){return[null,error]}const bodyText=await response.text().catch(()=>"");if(bodyText.trim().length===0){const parseError=new FetchError("json_parse_error","Response body is empty, cannot parse JSON",response,bodyText);logger_.error("fetchJson",parseError.reason,{error:parseError});return[null,parseError]}try{const data=JSON.parse(bodyText);if(options.requireJsonResponseWithOkTrue&&data.ok!==true){const parseError=new FetchError("json_response_error",'Response JSON "ok" property is not true',response,data);logger_.error("fetchJson",parseError.reason,{error:parseError});return[null,parseError]}return[data,null]}catch(err){const parseError=new FetchError("json_parse_error",err instanceof Error?err.message:"Failed to parse JSON response",response,bodyText);logger_.error("fetchJson",parseError.reason,{error:parseError});return[null,parseError]}}export{FetchError,cacheSupported,fetch,fetchJson};
|
|
4
4
|
//# sourceMappingURL=main.mjs.map
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alwatr/fetch",
|
|
3
3
|
"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.",
|
|
4
|
-
"version": "7.1.
|
|
4
|
+
"version": "7.1.3",
|
|
5
5
|
"author": "S. Ali Mihandoost <ali.mihandoost@gmail.com>",
|
|
6
6
|
"bugs": "https://github.com/Alwatr/nanolib/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@alwatr/delay": "6.0.
|
|
9
|
-
"@alwatr/global-this": "5.6.
|
|
10
|
-
"@alwatr/has-own": "5.6.
|
|
11
|
-
"@alwatr/http-primer": "6.0.
|
|
12
|
-
"@alwatr/logger": "6.0.
|
|
13
|
-
"@alwatr/parse-duration": "5.5.
|
|
8
|
+
"@alwatr/delay": "6.0.19",
|
|
9
|
+
"@alwatr/global-this": "5.6.8",
|
|
10
|
+
"@alwatr/has-own": "5.6.6",
|
|
11
|
+
"@alwatr/http-primer": "6.0.19",
|
|
12
|
+
"@alwatr/logger": "6.0.16",
|
|
13
|
+
"@alwatr/parse-duration": "5.5.28"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@alwatr/nano-build": "6.
|
|
16
|
+
"@alwatr/nano-build": "6.4.0",
|
|
17
17
|
"@alwatr/prettier-config": "6.0.1",
|
|
18
18
|
"@alwatr/tsconfig-base": "6.0.4",
|
|
19
19
|
"@alwatr/type-helper": "7.0.0",
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"sideEffects": false,
|
|
89
89
|
"type": "module",
|
|
90
90
|
"types": "./dist/main.d.ts",
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "35950cd5ceb1ae5a8ba4ac73852d286b7b3cd45f"
|
|
92
92
|
}
|