@vef-framework/core 2.0.8 → 2.0.9

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.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("@vef-framework/shared"),g=require("axios"),y=require("./errors.cjs"),m=/:(?<key>\w+)/g,$=/filename[^;=\n]*=(?<name>(?<quote>['"]).*?\2|[^;\n]*)/,f="X-Skip-Authentication",k="1";class R{#e;#s;#t=!1;#n=[];constructor(e){this.#s=e;const{baseUrl:s,timeout:n=1e3*30}=e;this.#e=g.create({baseURL:s,allowAbsoluteUrls:!0,timeout:n,headers:{"Content-Type":"application/json"},paramsSerializer:t=>u.encodeQueryString(t,{arrayFormat:"repeat",skipNulls:!0,charset:"utf-8"}),responseType:"json",responseEncoding:"utf-8",validateStatus(t){return t>=200&&t<300},withCredentials:!1,timeoutErrorMessage:"请求超时"}),this.initInterceptors()}initInterceptors(){this.#e.interceptors.request.use(this.handleRequest.bind(this),this.handleRequestError.bind(this)),this.#e.interceptors.response.use(this.handleResponse.bind(this),this.handleResponseError.bind(this))}isBelongsTo(e,s){return u.isArray(s)?s.includes(e):e===s}async handleRequest(e){const s=e.headers[f]===k;if(this.#t&&!s&&!await new Promise(t=>{this.#n.push(t)}))throw new Error("登录已过期, 请重新登录");return s?delete e.headers[f]:await this.setAccessToken(e),this.replacePathParams(e),e}handleRequestError(e){const{showErrorMessage:s}=this.#s,n=e instanceof Error?e.message:String(e);return s?s(`发起请求失败: ${n||"未知错误"}`):console.error(`[HttpClient] ❌ 发起请求失败: ${n||"未知错误"}`),Promise.reject(e)}handleResponse(e){const{showWarningMessage:s,okCode:n=0}=this.#s,{code:t,message:o,data:r}=e.data;if(this.isBelongsTo(t,n))return e;throw s?s(o):console.warn(`[HttpClient] ⚠️ [${e.config.method}: ${e.config.url}] 返回错误: ${o}`),new y.BusinessError(t,o,r)}async handleResponseError(e){const{showInfoMessage:s,showWarningMessage:n,showErrorMessage:t,tokenExpiredCode:o=[]}=this.#s;if(e instanceof g.CanceledError){if(e.response){const{method:i,url:c}=e.response.config;console.warn(`[HttpClient] ⚠️ [${i}: ${c}] 被取消`)}return}const{response:r}=e;if(r){const{status:i,config:c,data:l}=r,{code:d,message:a}=l,h=`[${c.method}: ${c.url}]`;switch(i){case 401:{if(this.isBelongsTo(d,o)){if(await this.tryRefreshToken()){await this.retryRequest(c);return}const w="登录已过期, 请重新登录";s?s(w):console.info(`[HttpClient] ℹ️ ${w}`)}await this.#s.onUnauthenticated?.();break}case 403:{n?.(`${a}, 请联系管理员为您开通`),console.warn(`[HttpClient] ⚠️ ${h} 访问被拒绝: ${a}`),await this.#s.onAccessDenied?.();break}case 400:{n?n(a):console.warn(`[HttpClient] ⚠️ ${h} 参数错误: ${a}`);break}default:t?t(a):console.error(`[HttpClient] ❌ ${h} 返回错误: ${a}`)}}else{const i=`请求失败: ${e.message||"未知错误"}`;t?t(i):console.error(`[HttpClient] ❌ ${i}`)}throw e}async setAccessToken(e){const{getAuthTokens:s}=this.#s;if(s){const t=(await s())?.accessToken;t&&(e.headers.Authorization=`Bearer ${t}`)}}replacePathParams(e){const{url:s,params:n={}}=e;return s&&m.test(s)&&(e.url=s.replaceAll(m,(t,o)=>{if(!Object.hasOwn(n,o))return console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 未在查询参数中定义, 请检查`),"unknown";const r=n[o];return u.isNullish(r)?(console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 在查询参数中为空, 请检查`),"unknown"):r})),e}async tryRefreshToken(){const{getAuthTokens:e,refreshToken:s,setAuthTokens:n}=this.#s;if(!e||!s||!n)return!1;this.#t=!0;let t=!1;try{const o=await e();if(!o)return!1;const r=await s(o);return await n(Object.freeze(r)),t=!0}catch(o){return console.error(`[HttpClient] ❌ 刷新令牌失败: ${o}`),!1}finally{this.#t=!1;for(const o of this.#n)o(t);this.#n=[]}}async retryRequest(e){const s={...e};return await this.setAccessToken(s),this.#e(s)}async get(e,s){return(await this.#e.get(e,s)).data}async post(e,s){const{data:n,...t}=s??{};return(await this.#e.post(e,n,t)).data}async put(e,s){const{data:n,...t}=s??{};return(await this.#e.put(e,n,t)).data}async delete(e,s){return(await this.#e.delete(e,s)).data}async upload(e,s){const{data:n,onProgress:t,...o}=s??{};return(await this.#e.postForm(e,n,{...o,onUploadProgress:u.isFunction(t)?t:void 0})).data}async download(e,s){const{onProgress:n,filename:t,...o}=s??{},{data:r,headers:i}=await this.#e.get(e,{...o,responseType:"blob",responseEncoding:"binary",onDownloadProgress:u.isFunction(n)?n:void 0});try{const l=JSON.parse(await r.text());throw new Error(l.message)}catch{}const c=i["content-disposition"];if(u.isString(c)){const l=$.exec(c);if(l&&l.groups){const{name:d}=l.groups,a=decodeURIComponent(d),h=URL.createObjectURL(r);try{const p=document.createElement("a");p.href=h,p.download=u.isFunction(t)?t(a):t??a,p.click()}finally{URL.revokeObjectURL(h)}}}}}exports.HttpClient=R;exports.skipAuthenticationHeader=f;exports.skipAuthenticationValue=k;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("@vef-framework/shared"),g=require("axios"),y=require("./errors.cjs"),m=/:(?<key>\w+)/g,$=/filename[^;=\n]*=(?<name>(?<quote>['"]).*?\2|[^;\n]*)/,f="X-Skip-Authentication",k="1";class R{#e;#s;#t=!1;#n=[];constructor(e){this.#s=e;const{baseUrl:s,timeout:n=1e3*30}=e;this.#e=g.create({baseURL:s,allowAbsoluteUrls:!0,timeout:n,headers:{"Content-Type":"application/json"},paramsSerializer:t=>u.encodeQueryString(t,{arrayFormat:"repeat",skipNulls:!0,charset:"utf-8"}),responseType:"json",responseEncoding:"utf-8",validateStatus(t){return t>=200&&t<300},withCredentials:!1,timeoutErrorMessage:"请求超时"}),this.initInterceptors()}initInterceptors(){this.#e.interceptors.request.use(this.handleRequest.bind(this),this.handleRequestError.bind(this)),this.#e.interceptors.response.use(this.handleResponse.bind(this),this.handleResponseError.bind(this))}isBelongsTo(e,s){return u.isArray(s)?s.includes(e):e===s}async handleRequest(e){const s=e.headers[f]===k;if(this.#t&&!s&&!await new Promise(t=>{this.#n.push(t)}))throw new Error("登录已过期, 请重新登录");return s?delete e.headers[f]:await this.setAccessToken(e),this.replacePathParams(e),e}handleRequestError(e){const{showErrorMessage:s}=this.#s,n=e instanceof Error?e.message:String(e);return s?s(`发起请求失败: ${n||"未知错误"}`):console.error(`[HttpClient] ❌ 发起请求失败: ${n||"未知错误"}`),Promise.reject(e)}handleResponse(e){const{showWarningMessage:s,okCode:n=0}=this.#s,{code:t,message:o,data:r}=e.data;if(this.isBelongsTo(t,n))return e;throw s?s(o):console.warn(`[HttpClient] ⚠️ [${e.config.method}: ${e.config.url}] 返回错误: ${o}`),new y.BusinessError(t,o,r)}async handleResponseError(e){const{showInfoMessage:s,showWarningMessage:n,showErrorMessage:t,tokenExpiredCode:o=[]}=this.#s;if(e instanceof g.CanceledError){if(e.response){const{method:a,url:c}=e.response.config;console.warn(`[HttpClient] ⚠️ [${a}: ${c}] 被取消`)}return}const{response:r}=e;if(r){const{status:a,config:c,data:l}=r,{code:d,message:i}=l,h=`[${c.method}: ${c.url}]`;switch(a){case 401:{if(this.isBelongsTo(d,o)){if(await this.tryRefreshToken())return this.retryRequest(c);const w="登录已过期, 请重新登录";s?s(w):console.info(`[HttpClient] ℹ️ ${w}`)}await this.#s.onUnauthenticated?.();break}case 403:{n?.(`${i}, 请联系管理员为您开通`),console.warn(`[HttpClient] ⚠️ ${h} 访问被拒绝: ${i}`),await this.#s.onAccessDenied?.();break}case 400:{n?n(i):console.warn(`[HttpClient] ⚠️ ${h} 参数错误: ${i}`);break}default:t?t(i):console.error(`[HttpClient] ❌ ${h} 返回错误: ${i}`)}}else{const a=`请求失败: ${e.message||"未知错误"}`;t?t(a):console.error(`[HttpClient] ❌ ${a}`)}throw e}async setAccessToken(e){const{getAuthTokens:s}=this.#s;if(s){const t=(await s())?.accessToken;t&&(e.headers.Authorization=`Bearer ${t}`)}}replacePathParams(e){const{url:s,params:n={}}=e;return s&&m.test(s)&&(e.url=s.replaceAll(m,(t,o)=>{if(!Object.hasOwn(n,o))return console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 未在查询参数中定义, 请检查`),"unknown";const r=n[o];return u.isNullish(r)?(console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 在查询参数中为空, 请检查`),"unknown"):r})),e}async tryRefreshToken(){const{getAuthTokens:e,refreshToken:s,setAuthTokens:n}=this.#s;if(!e||!s||!n)return!1;this.#t=!0;let t=!1;try{const o=await e();if(!o)return!1;const r=await s(o);return await n(Object.freeze(r)),t=!0}catch(o){return console.error(`[HttpClient] ❌ 刷新令牌失败: ${o}`),!1}finally{this.#t=!1;for(const o of this.#n)o(t);this.#n=[]}}async retryRequest(e){const s={...e};return await this.setAccessToken(s),this.#e(s)}async get(e,s){return(await this.#e.get(e,s)).data}async post(e,s){const{data:n,...t}=s??{};return(await this.#e.post(e,n,t)).data}async put(e,s){const{data:n,...t}=s??{};return(await this.#e.put(e,n,t)).data}async delete(e,s){return(await this.#e.delete(e,s)).data}async upload(e,s){const{data:n,onProgress:t,...o}=s??{};return(await this.#e.postForm(e,n,{...o,onUploadProgress:u.isFunction(t)?t:void 0})).data}async download(e,s){const{onProgress:n,filename:t,...o}=s??{},{data:r,headers:a}=await this.#e.get(e,{...o,responseType:"blob",responseEncoding:"binary",onDownloadProgress:u.isFunction(n)?n:void 0});try{const l=JSON.parse(await r.text());throw new Error(l.message)}catch{}const c=a["content-disposition"];if(u.isString(c)){const l=$.exec(c);if(l&&l.groups){const{name:d}=l.groups,i=decodeURIComponent(d),h=URL.createObjectURL(r);try{const p=document.createElement("a");p.href=h,p.download=u.isFunction(t)?t(i):t??i,p.click()}finally{URL.revokeObjectURL(h)}}}}}exports.HttpClient=R;exports.skipAuthenticationHeader=f;exports.skipAuthenticationValue=k;
@@ -139,10 +139,8 @@ class O {
139
139
  switch (i) {
140
140
  case 401: {
141
141
  if (this.isBelongsTo(p, o)) {
142
- if (await this.tryRefreshToken()) {
143
- await this.retryRequest(c);
144
- return;
145
- }
142
+ if (await this.tryRefreshToken())
143
+ return this.retryRequest(c);
146
144
  const f = "登录已过期, 请重新登录";
147
145
  s ? s(f) : console.info(`[HttpClient] ℹ️ ${f}`);
148
146
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vef-framework/core",
3
3
  "type": "module",
4
- "version": "2.0.8",
4
+ "version": "2.0.9",
5
5
  "private": false,
6
6
  "description": "Core features for VEF framework",
7
7
  "author": {
@@ -64,7 +64,7 @@
64
64
  "use-immer": "^0.11.0",
65
65
  "xstate": "^5.24.0",
66
66
  "zustand": "^5.0.8",
67
- "@vef-framework/shared": "2.0.8"
67
+ "@vef-framework/shared": "2.0.9"
68
68
  },
69
69
  "devDependencies": {
70
70
  "react": "^19.2.0"