@vef-framework/core 2.0.4 → 2.0.5
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/cjs/api/client.cjs +1 -171
- package/dist/cjs/api/constants.cjs +1 -13
- package/dist/cjs/api/helpers.cjs +1 -12
- package/dist/cjs/api/index.cjs +1 -14
- package/dist/cjs/auth/helpers.cjs +1 -19
- package/dist/cjs/auth/index.cjs +1 -10
- package/dist/cjs/common/index.cjs +1 -3
- package/dist/cjs/context/api-client.cjs +1 -25
- package/dist/cjs/context/app.cjs +1 -15
- package/dist/cjs/context/context-selector.cjs +1 -65
- package/dist/cjs/context/disabled.cjs +1 -15
- package/dist/cjs/context/index.cjs +1 -19
- package/dist/cjs/dnd/index.cjs +1 -102
- package/dist/cjs/http/client.cjs +1 -445
- package/dist/cjs/http/errors.cjs +1 -23
- package/dist/cjs/http/helpers.cjs +1 -17
- package/dist/cjs/http/index.cjs +1 -17
- package/dist/cjs/immer/index.cjs +1 -40
- package/dist/cjs/index.cjs +1 -306
- package/dist/cjs/motion/features.cjs +1 -13
- package/dist/cjs/motion/index.cjs +1 -48
- package/dist/cjs/motion/motion-provider.cjs +1 -29
- package/dist/cjs/query/constants.cjs +1 -8
- package/dist/cjs/query/helpers.cjs +1 -67
- package/dist/cjs/query/hooks.cjs +1 -52
- package/dist/cjs/query/index.cjs +1 -20
- package/dist/cjs/state/index.cjs +1 -41
- package/dist/cjs/state-machine/index.cjs +1 -35
- package/dist/cjs/store/bound.cjs +1 -42
- package/dist/cjs/store/index.cjs +1 -20
- package/dist/cjs/store/unbound.cjs +2 -73
- package/dist/cjs/store/use-deep.cjs +1 -17
- package/dist/es/api/client.js +72 -90
- package/dist/es/api/constants.js +7 -8
- package/dist/es/api/helpers.js +6 -7
- package/dist/es/api/index.js +8 -4
- package/dist/es/auth/helpers.js +9 -14
- package/dist/es/auth/index.js +4 -2
- package/dist/es/common/index.js +1 -1
- package/dist/es/context/api-client.js +16 -17
- package/dist/es/context/app.js +8 -9
- package/dist/es/context/context-selector.js +30 -39
- package/dist/es/context/disabled.js +9 -9
- package/dist/es/context/index.js +13 -5
- package/dist/es/dnd/index.js +30 -7
- package/dist/es/http/client.js +173 -253
- package/dist/es/http/errors.js +6 -9
- package/dist/es/http/helpers.js +10 -10
- package/dist/es/http/index.js +11 -4
- package/dist/es/immer/index.js +15 -8
- package/dist/es/index.js +122 -43
- package/dist/es/motion/features.js +4 -2
- package/dist/es/motion/index.js +11 -5
- package/dist/es/motion/motion-provider.js +15 -17
- package/dist/es/query/constants.js +4 -4
- package/dist/es/query/helpers.js +40 -45
- package/dist/es/query/hooks.js +29 -20
- package/dist/es/query/index.js +14 -4
- package/dist/es/state/index.js +11 -2
- package/dist/es/state-machine/index.js +14 -11
- package/dist/es/store/bound.js +24 -26
- package/dist/es/store/index.js +11 -5
- package/dist/es/store/unbound.js +44 -63
- package/dist/es/store/use-deep.js +10 -11
- package/package.json +3 -3
package/dist/cjs/http/client.cjs
CHANGED
|
@@ -1,445 +1 @@
|
|
|
1
|
-
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
5
|
-
|
|
6
|
-
const shared = require('@vef-framework/shared');
|
|
7
|
-
const axios = require('axios');
|
|
8
|
-
const errors = require('./errors.cjs');
|
|
9
|
-
|
|
10
|
-
const pathParamRegex = /:(?<key>\w+)/g;
|
|
11
|
-
const filenameRegex = /filename[^;=\n]*=(?<name>(?<quote>['"]).*?\2|[^;\n]*)/;
|
|
12
|
-
const skipAuthenticationHeader = "X-Skip-Authentication";
|
|
13
|
-
const skipAuthenticationValue = "1";
|
|
14
|
-
class HttpClient {
|
|
15
|
-
/**
|
|
16
|
-
* The axios instance.
|
|
17
|
-
*/
|
|
18
|
-
#axiosInstance;
|
|
19
|
-
/**
|
|
20
|
-
* The http client options.
|
|
21
|
-
*/
|
|
22
|
-
#options;
|
|
23
|
-
/**
|
|
24
|
-
* Indicates whether a token refresh is in progress.
|
|
25
|
-
*/
|
|
26
|
-
#isRefreshing = false;
|
|
27
|
-
/**
|
|
28
|
-
* Queue of pending requests waiting for token refresh to complete.
|
|
29
|
-
*/
|
|
30
|
-
#waitingQueue = [];
|
|
31
|
-
constructor(options) {
|
|
32
|
-
this.#options = options;
|
|
33
|
-
const {
|
|
34
|
-
baseUrl,
|
|
35
|
-
timeout = 1e3 * 30
|
|
36
|
-
} = options;
|
|
37
|
-
this.#axiosInstance = axios.create({
|
|
38
|
-
baseURL: baseUrl,
|
|
39
|
-
allowAbsoluteUrls: true,
|
|
40
|
-
timeout,
|
|
41
|
-
headers: {
|
|
42
|
-
"Content-Type": "application/json"
|
|
43
|
-
},
|
|
44
|
-
paramsSerializer: (params) => shared.encodeQueryString(
|
|
45
|
-
params,
|
|
46
|
-
{
|
|
47
|
-
arrayFormat: "repeat",
|
|
48
|
-
skipNulls: true,
|
|
49
|
-
charset: "utf-8"
|
|
50
|
-
}
|
|
51
|
-
),
|
|
52
|
-
responseType: "json",
|
|
53
|
-
responseEncoding: "utf-8",
|
|
54
|
-
validateStatus(status) {
|
|
55
|
-
return status >= 200 && status < 300;
|
|
56
|
-
},
|
|
57
|
-
withCredentials: false,
|
|
58
|
-
timeoutErrorMessage: "请求超时"
|
|
59
|
-
});
|
|
60
|
-
this.initInterceptors();
|
|
61
|
-
}
|
|
62
|
-
initInterceptors() {
|
|
63
|
-
this.#axiosInstance.interceptors.request.use(
|
|
64
|
-
this.handleRequest.bind(this),
|
|
65
|
-
this.handleRequestError.bind(this)
|
|
66
|
-
);
|
|
67
|
-
this.#axiosInstance.interceptors.response.use(
|
|
68
|
-
this.handleResponse.bind(this),
|
|
69
|
-
this.handleResponseError.bind(this)
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Check if the code belongs to the target.
|
|
74
|
-
*
|
|
75
|
-
* @param code - The code.
|
|
76
|
-
* @param target - The target.
|
|
77
|
-
* @returns The result.
|
|
78
|
-
*/
|
|
79
|
-
isBelongsTo(code, target) {
|
|
80
|
-
if (shared.isArray(target)) {
|
|
81
|
-
return target.includes(code);
|
|
82
|
-
}
|
|
83
|
-
return code === target;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Handle the request.
|
|
87
|
-
*
|
|
88
|
-
* @param config - The axios request config.
|
|
89
|
-
* @returns The axios request config.
|
|
90
|
-
*/
|
|
91
|
-
async handleRequest(config) {
|
|
92
|
-
const skipAuthentication = config.headers[skipAuthenticationHeader] === skipAuthenticationValue;
|
|
93
|
-
if (this.#isRefreshing && !skipAuthentication) {
|
|
94
|
-
const isSuccess = await new Promise((resolve) => {
|
|
95
|
-
this.#waitingQueue.push(resolve);
|
|
96
|
-
});
|
|
97
|
-
if (!isSuccess) {
|
|
98
|
-
throw new Error("登录已过期, 请重新登录");
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (skipAuthentication) {
|
|
102
|
-
delete config.headers[skipAuthenticationHeader];
|
|
103
|
-
} else {
|
|
104
|
-
await this.setAccessToken(config);
|
|
105
|
-
}
|
|
106
|
-
this.replacePathParams(config);
|
|
107
|
-
return config;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Handle the request error.
|
|
111
|
-
*
|
|
112
|
-
* @param error - The axios error.
|
|
113
|
-
*/
|
|
114
|
-
handleRequestError(error) {
|
|
115
|
-
const { showErrorMessage } = this.#options;
|
|
116
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
117
|
-
if (showErrorMessage) {
|
|
118
|
-
showErrorMessage(`发起请求失败: ${message || "未知错误"}`);
|
|
119
|
-
} else {
|
|
120
|
-
console.error(`[HttpClient] ❌ 发起请求失败: ${message || "未知错误"}`);
|
|
121
|
-
}
|
|
122
|
-
return Promise.reject(error);
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Handle the response.
|
|
126
|
-
*
|
|
127
|
-
* @param response - The axios response.
|
|
128
|
-
* @returns The axios response.
|
|
129
|
-
*/
|
|
130
|
-
handleResponse(response) {
|
|
131
|
-
const {
|
|
132
|
-
showWarningMessage,
|
|
133
|
-
okCode = 0
|
|
134
|
-
} = this.#options;
|
|
135
|
-
const {
|
|
136
|
-
code,
|
|
137
|
-
message,
|
|
138
|
-
data
|
|
139
|
-
} = response.data;
|
|
140
|
-
if (this.isBelongsTo(code, okCode)) {
|
|
141
|
-
return response;
|
|
142
|
-
}
|
|
143
|
-
if (showWarningMessage) {
|
|
144
|
-
showWarningMessage(message);
|
|
145
|
-
} else {
|
|
146
|
-
console.warn(`[HttpClient] ⚠️ [${response.config.method}: ${response.config.url}] 返回错误: ${message}`);
|
|
147
|
-
}
|
|
148
|
-
throw new errors.BusinessError(code, message, data);
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Handle the response error.
|
|
152
|
-
*
|
|
153
|
-
* @param error - The axios error.
|
|
154
|
-
*/
|
|
155
|
-
async handleResponseError(error) {
|
|
156
|
-
const {
|
|
157
|
-
showInfoMessage,
|
|
158
|
-
showWarningMessage,
|
|
159
|
-
showErrorMessage,
|
|
160
|
-
tokenExpiredCode = []
|
|
161
|
-
} = this.#options;
|
|
162
|
-
if (error instanceof axios.CanceledError) {
|
|
163
|
-
if (error.response) {
|
|
164
|
-
const { method, url } = error.response.config;
|
|
165
|
-
console.warn(`[HttpClient] ⚠️ [${method}: ${url}] 被取消`);
|
|
166
|
-
}
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
const { response } = error;
|
|
170
|
-
if (response) {
|
|
171
|
-
const {
|
|
172
|
-
status,
|
|
173
|
-
config,
|
|
174
|
-
data
|
|
175
|
-
} = response;
|
|
176
|
-
const { code, message } = data;
|
|
177
|
-
const requestInfo = `[${config.method}: ${config.url}]`;
|
|
178
|
-
switch (status) {
|
|
179
|
-
case 401: {
|
|
180
|
-
if (this.isBelongsTo(code, tokenExpiredCode)) {
|
|
181
|
-
const success = await this.tryRefreshToken();
|
|
182
|
-
if (success) {
|
|
183
|
-
await this.retryRequest(config);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
const expiredMessage = "登录已过期, 请重新登录";
|
|
187
|
-
if (showInfoMessage) {
|
|
188
|
-
showInfoMessage(expiredMessage);
|
|
189
|
-
} else {
|
|
190
|
-
console.info(`[HttpClient] ℹ️ ${expiredMessage}`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
await this.#options.onUnauthenticated?.();
|
|
194
|
-
break;
|
|
195
|
-
}
|
|
196
|
-
case 403: {
|
|
197
|
-
showWarningMessage?.(`${message}, 请联系管理员为您开通`);
|
|
198
|
-
console.warn(`[HttpClient] ⚠️ ${requestInfo} 访问被拒绝: ${message}`);
|
|
199
|
-
await this.#options.onAccessDenied?.();
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
case 400: {
|
|
203
|
-
if (showWarningMessage) {
|
|
204
|
-
showWarningMessage(message);
|
|
205
|
-
} else {
|
|
206
|
-
console.warn(`[HttpClient] ⚠️ ${requestInfo} 参数错误: ${message}`);
|
|
207
|
-
}
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
default: {
|
|
211
|
-
if (showErrorMessage) {
|
|
212
|
-
showErrorMessage(message);
|
|
213
|
-
} else {
|
|
214
|
-
console.error(`[HttpClient] ❌ ${requestInfo} 返回错误: ${message}`);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
} else {
|
|
219
|
-
const errorMessage = `请求失败: ${error.message || "未知错误"}`;
|
|
220
|
-
if (showErrorMessage) {
|
|
221
|
-
showErrorMessage(errorMessage);
|
|
222
|
-
} else {
|
|
223
|
-
console.error(`[HttpClient] ❌ ${errorMessage}`);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
throw error;
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* Injects access token into request Authorization header.
|
|
230
|
-
*
|
|
231
|
-
* @param config - The axios request config.
|
|
232
|
-
*/
|
|
233
|
-
async setAccessToken(config) {
|
|
234
|
-
const { getAuthTokens } = this.#options;
|
|
235
|
-
if (getAuthTokens) {
|
|
236
|
-
const tokens = await getAuthTokens();
|
|
237
|
-
const accessToken = tokens?.accessToken;
|
|
238
|
-
if (accessToken) {
|
|
239
|
-
config.headers.Authorization = `Bearer ${accessToken}`;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Replace the path parameters in the URL.
|
|
245
|
-
*
|
|
246
|
-
* @param config - The axios request config.
|
|
247
|
-
* @returns The axios request config.
|
|
248
|
-
*/
|
|
249
|
-
replacePathParams(config) {
|
|
250
|
-
const { url, params = {} } = config;
|
|
251
|
-
if (url && pathParamRegex.test(url)) {
|
|
252
|
-
config.url = url.replaceAll(pathParamRegex, (_, key) => {
|
|
253
|
-
if (!Object.hasOwn(params, key)) {
|
|
254
|
-
console.warn(`[HttpClient] ⚠️ 接口: ${url} 路径参数 ${key} 未在查询参数中定义, 请检查`);
|
|
255
|
-
return "unknown";
|
|
256
|
-
}
|
|
257
|
-
const value = params[key];
|
|
258
|
-
if (shared.isNullish(value)) {
|
|
259
|
-
console.warn(`[HttpClient] ⚠️ 接口: ${url} 路径参数 ${key} 在查询参数中为空, 请检查`);
|
|
260
|
-
return "unknown";
|
|
261
|
-
}
|
|
262
|
-
return value;
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
return config;
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* Try to refresh the token using the provided refresh callback.
|
|
269
|
-
*
|
|
270
|
-
* @returns True if token refresh succeeded, false otherwise.
|
|
271
|
-
*/
|
|
272
|
-
async tryRefreshToken() {
|
|
273
|
-
const {
|
|
274
|
-
getAuthTokens,
|
|
275
|
-
refreshToken,
|
|
276
|
-
setAuthTokens
|
|
277
|
-
} = this.#options;
|
|
278
|
-
if (!getAuthTokens || !refreshToken || !setAuthTokens) {
|
|
279
|
-
return false;
|
|
280
|
-
}
|
|
281
|
-
this.#isRefreshing = true;
|
|
282
|
-
let success = false;
|
|
283
|
-
try {
|
|
284
|
-
const currentTokens = await getAuthTokens();
|
|
285
|
-
if (!currentTokens) {
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
const newTokens = await refreshToken(currentTokens);
|
|
289
|
-
await setAuthTokens(Object.freeze(newTokens));
|
|
290
|
-
return success = true;
|
|
291
|
-
} catch (error) {
|
|
292
|
-
console.error(`[HttpClient] ❌ 刷新令牌失败: ${error}`);
|
|
293
|
-
return false;
|
|
294
|
-
} finally {
|
|
295
|
-
this.#isRefreshing = false;
|
|
296
|
-
for (const resolve of this.#waitingQueue) {
|
|
297
|
-
resolve(success);
|
|
298
|
-
}
|
|
299
|
-
this.#waitingQueue = [];
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Retry the request.
|
|
304
|
-
*
|
|
305
|
-
* @param config - The axios request config.
|
|
306
|
-
* @returns The axios response.
|
|
307
|
-
*/
|
|
308
|
-
async retryRequest(config) {
|
|
309
|
-
const newConfig = { ...config };
|
|
310
|
-
await this.setAccessToken(newConfig);
|
|
311
|
-
return this.#axiosInstance(newConfig);
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Get the resource.
|
|
315
|
-
*
|
|
316
|
-
* @param url - The url.
|
|
317
|
-
* @param options - The options for the request.
|
|
318
|
-
* @returns The response data.
|
|
319
|
-
*/
|
|
320
|
-
async get(url, options) {
|
|
321
|
-
const response = await this.#axiosInstance.get(
|
|
322
|
-
url,
|
|
323
|
-
options
|
|
324
|
-
);
|
|
325
|
-
return response.data;
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Post the resource.
|
|
329
|
-
*
|
|
330
|
-
* @param url - The url.
|
|
331
|
-
* @param options - The options for the request.
|
|
332
|
-
* @returns The response data.
|
|
333
|
-
*/
|
|
334
|
-
async post(url, options) {
|
|
335
|
-
const { data, ...restOptions } = options ?? {};
|
|
336
|
-
const response = await this.#axiosInstance.post(
|
|
337
|
-
url,
|
|
338
|
-
data,
|
|
339
|
-
restOptions
|
|
340
|
-
);
|
|
341
|
-
return response.data;
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Update the resource.
|
|
345
|
-
*
|
|
346
|
-
* @param url - The url.
|
|
347
|
-
* @param options - The options for the request.
|
|
348
|
-
* @returns The response data.
|
|
349
|
-
*/
|
|
350
|
-
async put(url, options) {
|
|
351
|
-
const { data, ...restOptions } = options ?? {};
|
|
352
|
-
const response = await this.#axiosInstance.put(
|
|
353
|
-
url,
|
|
354
|
-
data,
|
|
355
|
-
restOptions
|
|
356
|
-
);
|
|
357
|
-
return response.data;
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* Delete the resource.
|
|
361
|
-
*
|
|
362
|
-
* @param url - The url.
|
|
363
|
-
* @param options - The options for the request.
|
|
364
|
-
* @returns The response data.
|
|
365
|
-
*/
|
|
366
|
-
async delete(url, options) {
|
|
367
|
-
const response = await this.#axiosInstance.delete(
|
|
368
|
-
url,
|
|
369
|
-
options
|
|
370
|
-
);
|
|
371
|
-
return response.data;
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* Upload the file.
|
|
375
|
-
*
|
|
376
|
-
* @param url - The url.
|
|
377
|
-
* @param options - The options for the request.
|
|
378
|
-
* @returns The response data.
|
|
379
|
-
*/
|
|
380
|
-
async upload(url, options) {
|
|
381
|
-
const {
|
|
382
|
-
data,
|
|
383
|
-
onProgress,
|
|
384
|
-
...restOptions
|
|
385
|
-
} = options ?? {};
|
|
386
|
-
const response = await this.#axiosInstance.postForm(
|
|
387
|
-
url,
|
|
388
|
-
data,
|
|
389
|
-
{
|
|
390
|
-
...restOptions,
|
|
391
|
-
onUploadProgress: shared.isFunction(onProgress) ? onProgress : void 0
|
|
392
|
-
}
|
|
393
|
-
);
|
|
394
|
-
return response.data;
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* Download the file.
|
|
398
|
-
*
|
|
399
|
-
* @param url - The url.
|
|
400
|
-
* @param options - The options for the request.
|
|
401
|
-
* @returns The response data.
|
|
402
|
-
*/
|
|
403
|
-
async download(url, options) {
|
|
404
|
-
const {
|
|
405
|
-
onProgress,
|
|
406
|
-
filename,
|
|
407
|
-
...restOptions
|
|
408
|
-
} = options ?? {};
|
|
409
|
-
const { data, headers } = await this.#axiosInstance.get(
|
|
410
|
-
url,
|
|
411
|
-
{
|
|
412
|
-
...restOptions,
|
|
413
|
-
responseType: "blob",
|
|
414
|
-
responseEncoding: "binary",
|
|
415
|
-
onDownloadProgress: shared.isFunction(onProgress) ? onProgress : void 0
|
|
416
|
-
}
|
|
417
|
-
);
|
|
418
|
-
try {
|
|
419
|
-
const result = JSON.parse(await data.text());
|
|
420
|
-
throw new Error(result.message);
|
|
421
|
-
} catch {
|
|
422
|
-
}
|
|
423
|
-
const contentDisposition = headers["content-disposition"];
|
|
424
|
-
if (shared.isString(contentDisposition)) {
|
|
425
|
-
const matches = filenameRegex.exec(contentDisposition);
|
|
426
|
-
if (matches && matches.groups) {
|
|
427
|
-
const { name } = matches.groups;
|
|
428
|
-
const original = decodeURIComponent(name);
|
|
429
|
-
const objectUrl = URL.createObjectURL(data);
|
|
430
|
-
try {
|
|
431
|
-
const a = document.createElement("a");
|
|
432
|
-
a.href = objectUrl;
|
|
433
|
-
a.download = shared.isFunction(filename) ? filename(original) : filename ?? original;
|
|
434
|
-
a.click();
|
|
435
|
-
} finally {
|
|
436
|
-
URL.revokeObjectURL(objectUrl);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
exports.HttpClient = HttpClient;
|
|
444
|
-
exports.skipAuthenticationHeader = skipAuthenticationHeader;
|
|
445
|
-
exports.skipAuthenticationValue = skipAuthenticationValue;
|
|
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;
|
package/dist/cjs/http/errors.cjs
CHANGED
|
@@ -1,23 +1 @@
|
|
|
1
|
-
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
5
|
-
|
|
6
|
-
class BusinessError extends Error {
|
|
7
|
-
/**
|
|
8
|
-
* The business error code from the API response.
|
|
9
|
-
*/
|
|
10
|
-
code;
|
|
11
|
-
/**
|
|
12
|
-
* The original API response data.
|
|
13
|
-
*/
|
|
14
|
-
data;
|
|
15
|
-
constructor(code, message, data) {
|
|
16
|
-
super(message);
|
|
17
|
-
this.name = "BusinessError";
|
|
18
|
-
this.code = code;
|
|
19
|
-
this.data = data;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
exports.BusinessError = BusinessError;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class t extends Error{code;data;constructor(r,s,e){super(s),this.name="BusinessError",this.code=r,this.data=e}}exports.BusinessError=t;
|
|
@@ -1,17 +1 @@
|
|
|
1
|
-
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
5
|
-
|
|
6
|
-
const client = require('./client.cjs');
|
|
7
|
-
const errors = require('./errors.cjs');
|
|
8
|
-
|
|
9
|
-
function createHttpClient(options) {
|
|
10
|
-
return Object.freeze(new client.HttpClient(options));
|
|
11
|
-
}
|
|
12
|
-
function isBusinessError(error) {
|
|
13
|
-
return error instanceof errors.BusinessError;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
exports.createHttpClient = createHttpClient;
|
|
17
|
-
exports.isBusinessError = isBusinessError;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./client.cjs"),t=require("./errors.cjs");function n(e){return Object.freeze(new r.HttpClient(e))}function i(e){return e instanceof t.BusinessError}exports.createHttpClient=n;exports.isBusinessError=i;
|
package/dist/cjs/http/index.cjs
CHANGED
|
@@ -1,17 +1 @@
|
|
|
1
|
-
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
5
|
-
|
|
6
|
-
const client = require('./client.cjs');
|
|
7
|
-
const errors = require('./errors.cjs');
|
|
8
|
-
const helpers = require('./helpers.cjs');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
exports.HttpClient = client.HttpClient;
|
|
13
|
-
exports.skipAuthenticationHeader = client.skipAuthenticationHeader;
|
|
14
|
-
exports.skipAuthenticationValue = client.skipAuthenticationValue;
|
|
15
|
-
exports.BusinessError = errors.BusinessError;
|
|
16
|
-
exports.createHttpClient = helpers.createHttpClient;
|
|
17
|
-
exports.isBusinessError = helpers.isBusinessError;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./client.cjs"),r=require("./errors.cjs"),t=require("./helpers.cjs");exports.HttpClient=e.HttpClient;exports.skipAuthenticationHeader=e.skipAuthenticationHeader;exports.skipAuthenticationValue=e.skipAuthenticationValue;exports.BusinessError=r.BusinessError;exports.createHttpClient=t.createHttpClient;exports.isBusinessError=t.isBusinessError;
|
package/dist/cjs/immer/index.cjs
CHANGED
|
@@ -1,40 +1 @@
|
|
|
1
|
-
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
5
|
-
|
|
6
|
-
const immer = require('immer');
|
|
7
|
-
const useImmer = require('use-immer');
|
|
8
|
-
|
|
9
|
-
immer.enableMapSet();
|
|
10
|
-
immer.enablePatches();
|
|
11
|
-
immer.setAutoFreeze(false);
|
|
12
|
-
|
|
13
|
-
Object.defineProperty(exports, "applyPatches", {
|
|
14
|
-
enumerable: true,
|
|
15
|
-
get: () => immer.applyPatches
|
|
16
|
-
});
|
|
17
|
-
Object.defineProperty(exports, "currentState", {
|
|
18
|
-
enumerable: true,
|
|
19
|
-
get: () => immer.current
|
|
20
|
-
});
|
|
21
|
-
Object.defineProperty(exports, "originalState", {
|
|
22
|
-
enumerable: true,
|
|
23
|
-
get: () => immer.original
|
|
24
|
-
});
|
|
25
|
-
Object.defineProperty(exports, "produce", {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
get: () => immer.produce
|
|
28
|
-
});
|
|
29
|
-
Object.defineProperty(exports, "produceWithPatches", {
|
|
30
|
-
enumerable: true,
|
|
31
|
-
get: () => immer.produceWithPatches
|
|
32
|
-
});
|
|
33
|
-
Object.defineProperty(exports, "useImmer", {
|
|
34
|
-
enumerable: true,
|
|
35
|
-
get: () => useImmer.useImmer
|
|
36
|
-
});
|
|
37
|
-
Object.defineProperty(exports, "useImmerReducer", {
|
|
38
|
-
enumerable: true,
|
|
39
|
-
get: () => useImmer.useImmerReducer
|
|
40
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("immer"),r=require("use-immer");e.enableMapSet();e.enablePatches();e.setAutoFreeze(!1);Object.defineProperty(exports,"applyPatches",{enumerable:!0,get:()=>e.applyPatches});Object.defineProperty(exports,"currentState",{enumerable:!0,get:()=>e.current});Object.defineProperty(exports,"originalState",{enumerable:!0,get:()=>e.original});Object.defineProperty(exports,"produce",{enumerable:!0,get:()=>e.produce});Object.defineProperty(exports,"produceWithPatches",{enumerable:!0,get:()=>e.produceWithPatches});Object.defineProperty(exports,"useImmer",{enumerable:!0,get:()=>r.useImmer});Object.defineProperty(exports,"useImmerReducer",{enumerable:!0,get:()=>r.useImmerReducer});
|