@vef-framework/core 2.0.8 → 2.0.10

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"),$=require("./errors.cjs"),m=/:(?<key>\w+)/g,R=/filename[^;=\n]*=(?<name>(?<quote>['"]).*?\2|[^;\n]*)/,f="X-Skip-Authentication",k="1";class b{#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 $.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,p=`[${c.method}: ${c.url}]`;switch(a){case 401:{if(this.isBelongsTo(d,o)){let h;if(this.#t?h=await new Promise(y=>{this.#n.push(y)}):h=await this.tryRefreshToken(),h)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] ⚠️ ${p} 访问被拒绝: ${i}`),await this.#s.onAccessDenied?.();break}case 400:{n?n(i):console.warn(`[HttpClient] ⚠️ ${p} 参数错误: ${i}`);break}default:t?t(i):console.error(`[HttpClient] ❌ ${p} 返回错误: ${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=R.exec(c);if(l&&l.groups){const{name:d}=l.groups,i=decodeURIComponent(d),p=URL.createObjectURL(r);try{const h=document.createElement("a");h.href=p,h.download=u.isFunction(t)?t(i):t??i,h.click()}finally{URL.revokeObjectURL(p)}}}}}exports.HttpClient=b;exports.skipAuthenticationHeader=f;exports.skipAuthenticationValue=k;
@@ -1,8 +1,8 @@
1
- import { encodeQueryString as m, isArray as k, isNullish as y, isFunction as d, isString as $ } from "@vef-framework/shared";
2
- import R, { CanceledError as C } from "axios";
3
- import { BusinessError as T } from "./errors.js";
4
- const w = /:(?<key>\w+)/g, b = /filename[^;=\n]*=(?<name>(?<quote>['"]).*?\2|[^;\n]*)/, g = "X-Skip-Authentication", E = "1";
5
- class O {
1
+ import { encodeQueryString as k, isArray as y, isNullish as $, isFunction as d, isString as R } from "@vef-framework/shared";
2
+ import C, { CanceledError as T } from "axios";
3
+ import { BusinessError as b } from "./errors.js";
4
+ const w = /:(?<key>\w+)/g, E = /filename[^;=\n]*=(?<name>(?<quote>['"]).*?\2|[^;\n]*)/, g = "X-Skip-Authentication", A = "1";
5
+ class q {
6
6
  /**
7
7
  * The axios instance.
8
8
  */
@@ -25,14 +25,14 @@ class O {
25
25
  baseUrl: s,
26
26
  timeout: n = 1e3 * 30
27
27
  } = e;
28
- this.#e = R.create({
28
+ this.#e = C.create({
29
29
  baseURL: s,
30
30
  allowAbsoluteUrls: !0,
31
31
  timeout: n,
32
32
  headers: {
33
33
  "Content-Type": "application/json"
34
34
  },
35
- paramsSerializer: (t) => m(
35
+ paramsSerializer: (t) => k(
36
36
  t,
37
37
  {
38
38
  arrayFormat: "repeat",
@@ -66,7 +66,7 @@ class O {
66
66
  * @returns The result.
67
67
  */
68
68
  isBelongsTo(e, s) {
69
- return k(s) ? s.includes(e) : e === s;
69
+ return y(s) ? s.includes(e) : e === s;
70
70
  }
71
71
  /**
72
72
  * Handle the request.
@@ -75,7 +75,7 @@ class O {
75
75
  * @returns The axios request config.
76
76
  */
77
77
  async handleRequest(e) {
78
- const s = e.headers[g] === E;
78
+ const s = e.headers[g] === A;
79
79
  if (this.#t && !s && !await new Promise((t) => {
80
80
  this.#n.push(t);
81
81
  }))
@@ -108,7 +108,7 @@ class O {
108
108
  } = e.data;
109
109
  if (this.isBelongsTo(t, n))
110
110
  return e;
111
- throw s ? s(o) : console.warn(`[HttpClient] ⚠️ [${e.config.method}: ${e.config.url}] 返回错误: ${o}`), new T(t, o, r);
111
+ throw s ? s(o) : console.warn(`[HttpClient] ⚠️ [${e.config.method}: ${e.config.url}] 返回错误: ${o}`), new b(t, o, r);
112
112
  }
113
113
  /**
114
114
  * Handle the response error.
@@ -122,7 +122,7 @@ class O {
122
122
  showErrorMessage: t,
123
123
  tokenExpiredCode: o = []
124
124
  } = this.#s;
125
- if (e instanceof C) {
125
+ if (e instanceof T) {
126
126
  if (e.response) {
127
127
  const { method: i, url: c } = e.response.config;
128
128
  console.warn(`[HttpClient] ⚠️ [${i}: ${c}] 被取消`);
@@ -135,14 +135,15 @@ class O {
135
135
  status: i,
136
136
  config: c,
137
137
  data: l
138
- } = r, { code: p, message: a } = l, h = `[${c.method}: ${c.url}]`;
138
+ } = r, { code: p, message: a } = l, u = `[${c.method}: ${c.url}]`;
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
+ let h;
143
+ if (this.#t ? h = await new Promise((m) => {
144
+ this.#n.push(m);
145
+ }) : h = await this.tryRefreshToken(), h)
146
+ return this.retryRequest(c);
146
147
  const f = "登录已过期, 请重新登录";
147
148
  s ? s(f) : console.info(`[HttpClient] ℹ️ ${f}`);
148
149
  }
@@ -150,15 +151,15 @@ class O {
150
151
  break;
151
152
  }
152
153
  case 403: {
153
- n?.(`${a}, 请联系管理员为您开通`), console.warn(`[HttpClient] ⚠️ ${h} 访问被拒绝: ${a}`), await this.#s.onAccessDenied?.();
154
+ n?.(`${a}, 请联系管理员为您开通`), console.warn(`[HttpClient] ⚠️ ${u} 访问被拒绝: ${a}`), await this.#s.onAccessDenied?.();
154
155
  break;
155
156
  }
156
157
  case 400: {
157
- n ? n(a) : console.warn(`[HttpClient] ⚠️ ${h} 参数错误: ${a}`);
158
+ n ? n(a) : console.warn(`[HttpClient] ⚠️ ${u} 参数错误: ${a}`);
158
159
  break;
159
160
  }
160
161
  default:
161
- t ? t(a) : console.error(`[HttpClient] ❌ ${h} 返回错误: ${a}`);
162
+ t ? t(a) : console.error(`[HttpClient] ❌ ${u} 返回错误: ${a}`);
162
163
  }
163
164
  } else {
164
165
  const i = `请求失败: ${e.message || "未知错误"}`;
@@ -190,7 +191,7 @@ class O {
190
191
  if (!Object.hasOwn(n, o))
191
192
  return console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 未在查询参数中定义, 请检查`), "unknown";
192
193
  const r = n[o];
193
- return y(r) ? (console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 在查询参数中为空, 请检查`), "unknown") : r;
194
+ return $(r) ? (console.warn(`[HttpClient] ⚠️ 接口: ${s} 路径参数 ${o} 在查询参数中为空, 请检查`), "unknown") : r;
194
195
  })), e;
195
196
  }
196
197
  /**
@@ -338,22 +339,22 @@ class O {
338
339
  } catch {
339
340
  }
340
341
  const c = i["content-disposition"];
341
- if ($(c)) {
342
- const l = b.exec(c);
342
+ if (R(c)) {
343
+ const l = E.exec(c);
343
344
  if (l && l.groups) {
344
- const { name: p } = l.groups, a = decodeURIComponent(p), h = URL.createObjectURL(r);
345
+ const { name: p } = l.groups, a = decodeURIComponent(p), u = URL.createObjectURL(r);
345
346
  try {
346
- const u = document.createElement("a");
347
- u.href = h, u.download = d(t) ? t(a) : t ?? a, u.click();
347
+ const h = document.createElement("a");
348
+ h.href = u, h.download = d(t) ? t(a) : t ?? a, h.click();
348
349
  } finally {
349
- URL.revokeObjectURL(h);
350
+ URL.revokeObjectURL(u);
350
351
  }
351
352
  }
352
353
  }
353
354
  }
354
355
  }
355
356
  export {
356
- O as HttpClient,
357
+ q as HttpClient,
357
358
  g as skipAuthenticationHeader,
358
- E as skipAuthenticationValue
359
+ A as skipAuthenticationValue
359
360
  };
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.10",
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.10"
68
68
  },
69
69
  "devDependencies": {
70
70
  "react": "^19.2.0"