@kevisual/query 0.0.46 → 0.0.48
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/query-adapter.d.ts +1 -13
- package/dist/query-adapter.js +19 -17
- package/dist/query-api.d.ts +15 -17
- package/dist/query-api.js +13949 -176
- package/dist/query-browser.d.ts +5 -23
- package/dist/query-browser.js +42 -53
- package/dist/query.d.ts +6 -27
- package/dist/query.js +42 -39
- package/package.json +2 -2
- package/src/adapter.ts +20 -29
- package/src/create-query/index.ts +9 -0
- package/src/query-api.ts +17 -5
- package/src/query-browser.ts +1 -25
- package/src/query.ts +27 -38
package/dist/query-browser.d.ts
CHANGED
|
@@ -13,14 +13,6 @@ type AdapterOpts = {
|
|
|
13
13
|
body?: Record<string, any> | FormData;
|
|
14
14
|
timeout?: number;
|
|
15
15
|
method?: Method;
|
|
16
|
-
/**
|
|
17
|
-
* @deprecated use responseType
|
|
18
|
-
*/
|
|
19
|
-
isBlob?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* @deprecated use responseType
|
|
22
|
-
*/
|
|
23
|
-
isText?: boolean;
|
|
24
16
|
/**
|
|
25
17
|
* 响应类型,
|
|
26
18
|
* */
|
|
@@ -118,6 +110,8 @@ type QueryOptions = {
|
|
|
118
110
|
headers?: Record<string, string>;
|
|
119
111
|
timeout?: number;
|
|
120
112
|
isClient?: boolean;
|
|
113
|
+
tokenName?: string;
|
|
114
|
+
storage?: Storage;
|
|
121
115
|
beforeRequest?: Fn;
|
|
122
116
|
};
|
|
123
117
|
type Data = {
|
|
@@ -148,10 +142,7 @@ declare const wrapperError: ({ code, message }: {
|
|
|
148
142
|
message?: string;
|
|
149
143
|
}) => {
|
|
150
144
|
code: number;
|
|
151
|
-
success: boolean;
|
|
152
145
|
message: string;
|
|
153
|
-
showError: (fn?: () => void) => void;
|
|
154
|
-
noMsg: boolean;
|
|
155
146
|
};
|
|
156
147
|
/**
|
|
157
148
|
* const query = new Query();
|
|
@@ -180,10 +171,9 @@ declare class Query {
|
|
|
180
171
|
*/
|
|
181
172
|
stop?: boolean;
|
|
182
173
|
qws: QueryWs;
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
isClient: boolean;
|
|
174
|
+
tokenName: string;
|
|
175
|
+
storage: Storage;
|
|
176
|
+
token: string;
|
|
187
177
|
constructor(opts?: QueryOptions);
|
|
188
178
|
setQueryWs(qws: QueryWs): void;
|
|
189
179
|
/**
|
|
@@ -251,18 +241,10 @@ type QueryOpts = {
|
|
|
251
241
|
* 前端调用后端QueryRouter, 封装 beforeRequest 和 wss
|
|
252
242
|
*/
|
|
253
243
|
declare class QueryClient extends Query {
|
|
254
|
-
tokenName: string;
|
|
255
|
-
storage: Storage;
|
|
256
|
-
token: string;
|
|
257
244
|
constructor(opts?: QueryOptions & {
|
|
258
|
-
tokenName?: string;
|
|
259
|
-
storage?: Storage;
|
|
260
245
|
io?: boolean;
|
|
261
246
|
});
|
|
262
247
|
createWs(opts?: QueryWsOpts): void;
|
|
263
|
-
getToken(): string;
|
|
264
|
-
saveToken(token: string): void;
|
|
265
|
-
removeToken(): void;
|
|
266
248
|
}
|
|
267
249
|
|
|
268
250
|
export { BaseQuery, Query, QueryClient, QueryWs, adapter, wrapperError };
|
package/dist/query-browser.js
CHANGED
|
@@ -2,19 +2,13 @@
|
|
|
2
2
|
var isTextForContentType = (contentType) => {
|
|
3
3
|
if (!contentType)
|
|
4
4
|
return false;
|
|
5
|
-
const textTypes = ["text/", "xml", "html", "javascript", "css", "csv", "plain", "x-www-form-urlencoded", "md"];
|
|
5
|
+
const textTypes = ["text/", "xml", "html", "javascript", "css", "csv", "plain", "x-www-form-urlencoded", "md", "json"];
|
|
6
6
|
return textTypes.some((type) => contentType.includes(type));
|
|
7
7
|
};
|
|
8
8
|
var adapter = async (opts = {}, overloadOpts) => {
|
|
9
9
|
const controller = new AbortController;
|
|
10
10
|
const signal = controller.signal;
|
|
11
11
|
const isPostFile = opts.isPostFile || false;
|
|
12
|
-
let responseType = opts.responseType || "json";
|
|
13
|
-
if (opts.isBlob) {
|
|
14
|
-
responseType = "blob";
|
|
15
|
-
} else if (opts.isText) {
|
|
16
|
-
responseType = "text";
|
|
17
|
-
}
|
|
18
12
|
const timeout = opts.timeout || 60000 * 3;
|
|
19
13
|
const timer = setTimeout(() => {
|
|
20
14
|
controller.abort();
|
|
@@ -73,21 +67,31 @@ var adapter = async (opts = {}, overloadOpts) => {
|
|
|
73
67
|
headers
|
|
74
68
|
}).then(async (response) => {
|
|
75
69
|
const contentType = response.headers.get("Content-Type");
|
|
76
|
-
if (responseType === "blob") {
|
|
77
|
-
return await response.blob();
|
|
78
|
-
}
|
|
79
|
-
const isText = responseType === "text";
|
|
80
70
|
const isJson = contentType && contentType.includes("application/json");
|
|
81
|
-
|
|
82
|
-
|
|
71
|
+
const isSuccess = response.ok;
|
|
72
|
+
if (isJson) {
|
|
73
|
+
const json = await response.json();
|
|
74
|
+
if (json?.code) {
|
|
75
|
+
return json;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
code: isSuccess ? 200 : response.status,
|
|
79
|
+
status: response.status,
|
|
80
|
+
data: json
|
|
81
|
+
};
|
|
83
82
|
} else if (isTextForContentType(contentType)) {
|
|
84
83
|
return {
|
|
85
|
-
code: response.status,
|
|
84
|
+
code: isSuccess ? 200 : response.status,
|
|
86
85
|
status: response.status,
|
|
87
86
|
data: await response.text()
|
|
88
87
|
};
|
|
89
88
|
} else {
|
|
90
|
-
return
|
|
89
|
+
return {
|
|
90
|
+
code: isSuccess ? 200 : response.status,
|
|
91
|
+
status: response.status,
|
|
92
|
+
data: "非文本非JSON响应, 请手动处理response。",
|
|
93
|
+
response
|
|
94
|
+
};
|
|
91
95
|
}
|
|
92
96
|
}).catch((err) => {
|
|
93
97
|
if (err.name === "AbortError") {
|
|
@@ -306,10 +310,7 @@ class QueryWs {
|
|
|
306
310
|
var wrapperError = ({ code, message }) => {
|
|
307
311
|
const result = {
|
|
308
312
|
code: code || 500,
|
|
309
|
-
|
|
310
|
-
message: message || "api request error",
|
|
311
|
-
showError: (fn) => {},
|
|
312
|
-
noMsg: true
|
|
313
|
+
message: message || "请求错误"
|
|
313
314
|
};
|
|
314
315
|
return result;
|
|
315
316
|
};
|
|
@@ -323,9 +324,13 @@ class Query {
|
|
|
323
324
|
timeout;
|
|
324
325
|
stop;
|
|
325
326
|
qws;
|
|
326
|
-
|
|
327
|
+
tokenName;
|
|
328
|
+
storage;
|
|
329
|
+
token;
|
|
327
330
|
constructor(opts) {
|
|
328
331
|
this.adapter = opts?.adapter || adapter;
|
|
332
|
+
this.tokenName = opts?.tokenName || "token";
|
|
333
|
+
this.storage = opts?.storage || globalThis?.localStorage;
|
|
329
334
|
const defaultURL = opts?.isClient ? "/client/router" : "/api/router";
|
|
330
335
|
this.url = opts?.url || defaultURL;
|
|
331
336
|
this.headers = opts?.headers || {
|
|
@@ -336,7 +341,7 @@ class Query {
|
|
|
336
341
|
this.beforeRequest = opts.beforeRequest;
|
|
337
342
|
} else {
|
|
338
343
|
this.beforeRequest = async (opts2) => {
|
|
339
|
-
const token =
|
|
344
|
+
const token = this.token || this.storage?.getItem?.(this.tokenName);
|
|
340
345
|
if (token) {
|
|
341
346
|
opts2.headers = {
|
|
342
347
|
...opts2.headers,
|
|
@@ -358,7 +363,6 @@ class Query {
|
|
|
358
363
|
}
|
|
359
364
|
async post(body, options) {
|
|
360
365
|
const url = options?.url || this.url;
|
|
361
|
-
console.log("query post", url, body, options);
|
|
362
366
|
const { headers, adapter: adapter2, beforeRequest, afterResponse, timeout, ...rest } = options || {};
|
|
363
367
|
const _headers = { ...this.headers, ...headers };
|
|
364
368
|
const _adapter = adapter2 || this.adapter;
|
|
@@ -378,7 +382,7 @@ class Query {
|
|
|
378
382
|
if (res === false) {
|
|
379
383
|
return wrapperError({
|
|
380
384
|
code: 500,
|
|
381
|
-
message: "
|
|
385
|
+
message: "请求取消",
|
|
382
386
|
req
|
|
383
387
|
});
|
|
384
388
|
}
|
|
@@ -387,13 +391,13 @@ class Query {
|
|
|
387
391
|
console.error("request beforeFn error", e, req);
|
|
388
392
|
return wrapperError({
|
|
389
393
|
code: 500,
|
|
390
|
-
message: "
|
|
394
|
+
message: "请求在请求前处理时发生错误",
|
|
391
395
|
req
|
|
392
396
|
});
|
|
393
397
|
}
|
|
394
398
|
if (this.stop && !options?.noStop) {
|
|
395
399
|
const that = this;
|
|
396
|
-
await new Promise((resolve) => {
|
|
400
|
+
const res = await new Promise((resolve) => {
|
|
397
401
|
let timer = 0;
|
|
398
402
|
const detect = setInterval(() => {
|
|
399
403
|
if (!that.stop) {
|
|
@@ -401,11 +405,20 @@ class Query {
|
|
|
401
405
|
resolve(true);
|
|
402
406
|
}
|
|
403
407
|
timer++;
|
|
404
|
-
if (timer >
|
|
405
|
-
console.error("
|
|
408
|
+
if (timer > 5) {
|
|
409
|
+
console.error("等待请求失败:", req.url, timer);
|
|
410
|
+
clearInterval(detect);
|
|
411
|
+
resolve(false);
|
|
406
412
|
}
|
|
407
413
|
}, 1000);
|
|
408
414
|
});
|
|
415
|
+
if (!res) {
|
|
416
|
+
return wrapperError({
|
|
417
|
+
code: 500,
|
|
418
|
+
message: "请求取消,可能是因为用户未登录或者token过期",
|
|
419
|
+
req
|
|
420
|
+
});
|
|
421
|
+
}
|
|
409
422
|
}
|
|
410
423
|
return _adapter(req).then(async (res) => {
|
|
411
424
|
try {
|
|
@@ -418,10 +431,10 @@ class Query {
|
|
|
418
431
|
}
|
|
419
432
|
return res;
|
|
420
433
|
} catch (e) {
|
|
421
|
-
console.error("
|
|
434
|
+
console.error("请求在响应后处理时发生错误", e, req);
|
|
422
435
|
return wrapperError({
|
|
423
436
|
code: 500,
|
|
424
|
-
message: "
|
|
437
|
+
message: "请求在响应后处理时发生错误",
|
|
425
438
|
req
|
|
426
439
|
});
|
|
427
440
|
}
|
|
@@ -485,23 +498,8 @@ class BaseQuery {
|
|
|
485
498
|
|
|
486
499
|
// src/query-browser.ts
|
|
487
500
|
class QueryClient extends Query {
|
|
488
|
-
tokenName;
|
|
489
|
-
storage;
|
|
490
|
-
token;
|
|
491
501
|
constructor(opts) {
|
|
492
502
|
super(opts);
|
|
493
|
-
this.tokenName = opts?.tokenName || "token";
|
|
494
|
-
this.storage = opts?.storage || globalThis.localStorage;
|
|
495
|
-
this.beforeRequest = async (opts2) => {
|
|
496
|
-
const token = this.token || this.getToken();
|
|
497
|
-
if (token) {
|
|
498
|
-
opts2.headers = {
|
|
499
|
-
...opts2.headers,
|
|
500
|
-
Authorization: `Bearer ${token}`
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
return opts2;
|
|
504
|
-
};
|
|
505
503
|
if (opts?.io) {
|
|
506
504
|
this.createWs();
|
|
507
505
|
}
|
|
@@ -509,15 +507,6 @@ class QueryClient extends Query {
|
|
|
509
507
|
createWs(opts) {
|
|
510
508
|
this.qws = new QueryWs({ url: this.url, ...opts });
|
|
511
509
|
}
|
|
512
|
-
getToken() {
|
|
513
|
-
return this.storage.getItem(this.tokenName);
|
|
514
|
-
}
|
|
515
|
-
saveToken(token) {
|
|
516
|
-
this.storage.setItem(this.tokenName, token);
|
|
517
|
-
}
|
|
518
|
-
removeToken() {
|
|
519
|
-
this.storage.removeItem(this.tokenName);
|
|
520
|
-
}
|
|
521
510
|
}
|
|
522
511
|
export {
|
|
523
512
|
wrapperError,
|
package/dist/query.d.ts
CHANGED
|
@@ -13,14 +13,6 @@ type AdapterOpts = {
|
|
|
13
13
|
body?: Record<string, any> | FormData;
|
|
14
14
|
timeout?: number;
|
|
15
15
|
method?: Method;
|
|
16
|
-
/**
|
|
17
|
-
* @deprecated use responseType
|
|
18
|
-
*/
|
|
19
|
-
isBlob?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* @deprecated use responseType
|
|
22
|
-
*/
|
|
23
|
-
isText?: boolean;
|
|
24
16
|
/**
|
|
25
17
|
* 响应类型,
|
|
26
18
|
* */
|
|
@@ -118,6 +110,8 @@ type QueryOptions = {
|
|
|
118
110
|
headers?: Record<string, string>;
|
|
119
111
|
timeout?: number;
|
|
120
112
|
isClient?: boolean;
|
|
113
|
+
tokenName?: string;
|
|
114
|
+
storage?: Storage;
|
|
121
115
|
beforeRequest?: Fn;
|
|
122
116
|
};
|
|
123
117
|
type Data = {
|
|
@@ -143,26 +137,12 @@ type DataOpts = Partial<QueryOpts> & {
|
|
|
143
137
|
*/
|
|
144
138
|
noStop?: boolean;
|
|
145
139
|
};
|
|
146
|
-
/**
|
|
147
|
-
* 设置基础响应, 设置 success 和 showError,
|
|
148
|
-
* success 是 code 是否等于 200
|
|
149
|
-
* showError 是 如果 success 为 false 且 noMsg 为 false, 则调用 showError
|
|
150
|
-
* @param res 响应
|
|
151
|
-
*/
|
|
152
|
-
declare const setBaseResponse: (res: Partial<Result & {
|
|
153
|
-
success?: boolean;
|
|
154
|
-
showError?: (fn?: () => void) => void;
|
|
155
|
-
noMsg?: boolean;
|
|
156
|
-
}>) => Result;
|
|
157
140
|
declare const wrapperError: ({ code, message }: {
|
|
158
141
|
code?: number;
|
|
159
142
|
message?: string;
|
|
160
143
|
}) => {
|
|
161
144
|
code: number;
|
|
162
|
-
success: boolean;
|
|
163
145
|
message: string;
|
|
164
|
-
showError: (fn?: () => void) => void;
|
|
165
|
-
noMsg: boolean;
|
|
166
146
|
};
|
|
167
147
|
/**
|
|
168
148
|
* const query = new Query();
|
|
@@ -191,10 +171,9 @@ declare class Query {
|
|
|
191
171
|
*/
|
|
192
172
|
stop?: boolean;
|
|
193
173
|
qws: QueryWs;
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
isClient: boolean;
|
|
174
|
+
tokenName: string;
|
|
175
|
+
storage: Storage;
|
|
176
|
+
token: string;
|
|
198
177
|
constructor(opts?: QueryOptions);
|
|
199
178
|
setQueryWs(qws: QueryWs): void;
|
|
200
179
|
/**
|
|
@@ -251,5 +230,5 @@ declare class BaseQuery<T extends Query = Query, R extends {
|
|
|
251
230
|
get<R = any, P = any>(data: P, options?: DataOpts): Promise<Result<R>>;
|
|
252
231
|
}
|
|
253
232
|
|
|
254
|
-
export { BaseQuery, Query, adapter,
|
|
233
|
+
export { BaseQuery, Query, adapter, wrapperError };
|
|
255
234
|
export type { Data, DataOpts, Fn, QueryOptions, QueryOpts, Result };
|
package/dist/query.js
CHANGED
|
@@ -2,19 +2,13 @@
|
|
|
2
2
|
var isTextForContentType = (contentType) => {
|
|
3
3
|
if (!contentType)
|
|
4
4
|
return false;
|
|
5
|
-
const textTypes = ["text/", "xml", "html", "javascript", "css", "csv", "plain", "x-www-form-urlencoded", "md"];
|
|
5
|
+
const textTypes = ["text/", "xml", "html", "javascript", "css", "csv", "plain", "x-www-form-urlencoded", "md", "json"];
|
|
6
6
|
return textTypes.some((type) => contentType.includes(type));
|
|
7
7
|
};
|
|
8
8
|
var adapter = async (opts = {}, overloadOpts) => {
|
|
9
9
|
const controller = new AbortController;
|
|
10
10
|
const signal = controller.signal;
|
|
11
11
|
const isPostFile = opts.isPostFile || false;
|
|
12
|
-
let responseType = opts.responseType || "json";
|
|
13
|
-
if (opts.isBlob) {
|
|
14
|
-
responseType = "blob";
|
|
15
|
-
} else if (opts.isText) {
|
|
16
|
-
responseType = "text";
|
|
17
|
-
}
|
|
18
12
|
const timeout = opts.timeout || 60000 * 3;
|
|
19
13
|
const timer = setTimeout(() => {
|
|
20
14
|
controller.abort();
|
|
@@ -73,21 +67,31 @@ var adapter = async (opts = {}, overloadOpts) => {
|
|
|
73
67
|
headers
|
|
74
68
|
}).then(async (response) => {
|
|
75
69
|
const contentType = response.headers.get("Content-Type");
|
|
76
|
-
if (responseType === "blob") {
|
|
77
|
-
return await response.blob();
|
|
78
|
-
}
|
|
79
|
-
const isText = responseType === "text";
|
|
80
70
|
const isJson = contentType && contentType.includes("application/json");
|
|
81
|
-
|
|
82
|
-
|
|
71
|
+
const isSuccess = response.ok;
|
|
72
|
+
if (isJson) {
|
|
73
|
+
const json = await response.json();
|
|
74
|
+
if (json?.code) {
|
|
75
|
+
return json;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
code: isSuccess ? 200 : response.status,
|
|
79
|
+
status: response.status,
|
|
80
|
+
data: json
|
|
81
|
+
};
|
|
83
82
|
} else if (isTextForContentType(contentType)) {
|
|
84
83
|
return {
|
|
85
|
-
code: response.status,
|
|
84
|
+
code: isSuccess ? 200 : response.status,
|
|
86
85
|
status: response.status,
|
|
87
86
|
data: await response.text()
|
|
88
87
|
};
|
|
89
88
|
} else {
|
|
90
|
-
return
|
|
89
|
+
return {
|
|
90
|
+
code: isSuccess ? 200 : response.status,
|
|
91
|
+
status: response.status,
|
|
92
|
+
data: "非文本非JSON响应, 请手动处理response。",
|
|
93
|
+
response
|
|
94
|
+
};
|
|
91
95
|
}
|
|
92
96
|
}).catch((err) => {
|
|
93
97
|
if (err.name === "AbortError") {
|
|
@@ -106,22 +110,10 @@ var adapter = async (opts = {}, overloadOpts) => {
|
|
|
106
110
|
};
|
|
107
111
|
|
|
108
112
|
// src/query.ts
|
|
109
|
-
var setBaseResponse = (res) => {
|
|
110
|
-
res.success = res.code === 200;
|
|
111
|
-
res.showError = (fn) => {
|
|
112
|
-
if (!res.success && !res.noMsg) {
|
|
113
|
-
fn?.();
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
return res;
|
|
117
|
-
};
|
|
118
113
|
var wrapperError = ({ code, message }) => {
|
|
119
114
|
const result = {
|
|
120
115
|
code: code || 500,
|
|
121
|
-
|
|
122
|
-
message: message || "api request error",
|
|
123
|
-
showError: (fn) => {},
|
|
124
|
-
noMsg: true
|
|
116
|
+
message: message || "请求错误"
|
|
125
117
|
};
|
|
126
118
|
return result;
|
|
127
119
|
};
|
|
@@ -135,9 +127,13 @@ class Query {
|
|
|
135
127
|
timeout;
|
|
136
128
|
stop;
|
|
137
129
|
qws;
|
|
138
|
-
|
|
130
|
+
tokenName;
|
|
131
|
+
storage;
|
|
132
|
+
token;
|
|
139
133
|
constructor(opts) {
|
|
140
134
|
this.adapter = opts?.adapter || adapter;
|
|
135
|
+
this.tokenName = opts?.tokenName || "token";
|
|
136
|
+
this.storage = opts?.storage || globalThis?.localStorage;
|
|
141
137
|
const defaultURL = opts?.isClient ? "/client/router" : "/api/router";
|
|
142
138
|
this.url = opts?.url || defaultURL;
|
|
143
139
|
this.headers = opts?.headers || {
|
|
@@ -148,7 +144,7 @@ class Query {
|
|
|
148
144
|
this.beforeRequest = opts.beforeRequest;
|
|
149
145
|
} else {
|
|
150
146
|
this.beforeRequest = async (opts2) => {
|
|
151
|
-
const token =
|
|
147
|
+
const token = this.token || this.storage?.getItem?.(this.tokenName);
|
|
152
148
|
if (token) {
|
|
153
149
|
opts2.headers = {
|
|
154
150
|
...opts2.headers,
|
|
@@ -170,7 +166,6 @@ class Query {
|
|
|
170
166
|
}
|
|
171
167
|
async post(body, options) {
|
|
172
168
|
const url = options?.url || this.url;
|
|
173
|
-
console.log("query post", url, body, options);
|
|
174
169
|
const { headers, adapter: adapter2, beforeRequest, afterResponse, timeout, ...rest } = options || {};
|
|
175
170
|
const _headers = { ...this.headers, ...headers };
|
|
176
171
|
const _adapter = adapter2 || this.adapter;
|
|
@@ -190,7 +185,7 @@ class Query {
|
|
|
190
185
|
if (res === false) {
|
|
191
186
|
return wrapperError({
|
|
192
187
|
code: 500,
|
|
193
|
-
message: "
|
|
188
|
+
message: "请求取消",
|
|
194
189
|
req
|
|
195
190
|
});
|
|
196
191
|
}
|
|
@@ -199,13 +194,13 @@ class Query {
|
|
|
199
194
|
console.error("request beforeFn error", e, req);
|
|
200
195
|
return wrapperError({
|
|
201
196
|
code: 500,
|
|
202
|
-
message: "
|
|
197
|
+
message: "请求在请求前处理时发生错误",
|
|
203
198
|
req
|
|
204
199
|
});
|
|
205
200
|
}
|
|
206
201
|
if (this.stop && !options?.noStop) {
|
|
207
202
|
const that = this;
|
|
208
|
-
await new Promise((resolve) => {
|
|
203
|
+
const res = await new Promise((resolve) => {
|
|
209
204
|
let timer = 0;
|
|
210
205
|
const detect = setInterval(() => {
|
|
211
206
|
if (!that.stop) {
|
|
@@ -213,11 +208,20 @@ class Query {
|
|
|
213
208
|
resolve(true);
|
|
214
209
|
}
|
|
215
210
|
timer++;
|
|
216
|
-
if (timer >
|
|
217
|
-
console.error("
|
|
211
|
+
if (timer > 5) {
|
|
212
|
+
console.error("等待请求失败:", req.url, timer);
|
|
213
|
+
clearInterval(detect);
|
|
214
|
+
resolve(false);
|
|
218
215
|
}
|
|
219
216
|
}, 1000);
|
|
220
217
|
});
|
|
218
|
+
if (!res) {
|
|
219
|
+
return wrapperError({
|
|
220
|
+
code: 500,
|
|
221
|
+
message: "请求取消,可能是因为用户未登录或者token过期",
|
|
222
|
+
req
|
|
223
|
+
});
|
|
224
|
+
}
|
|
221
225
|
}
|
|
222
226
|
return _adapter(req).then(async (res) => {
|
|
223
227
|
try {
|
|
@@ -230,10 +234,10 @@ class Query {
|
|
|
230
234
|
}
|
|
231
235
|
return res;
|
|
232
236
|
} catch (e) {
|
|
233
|
-
console.error("
|
|
237
|
+
console.error("请求在响应后处理时发生错误", e, req);
|
|
234
238
|
return wrapperError({
|
|
235
239
|
code: 500,
|
|
236
|
-
message: "
|
|
240
|
+
message: "请求在响应后处理时发生错误",
|
|
237
241
|
req
|
|
238
242
|
});
|
|
239
243
|
}
|
|
@@ -296,7 +300,6 @@ class BaseQuery {
|
|
|
296
300
|
}
|
|
297
301
|
export {
|
|
298
302
|
wrapperError,
|
|
299
|
-
setBaseResponse,
|
|
300
303
|
adapter,
|
|
301
304
|
Query,
|
|
302
305
|
BaseQuery
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevisual/query",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.48",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "npm run clean && bun run bun.config.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"description": "",
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@kevisual/code-builder": "^0.0.6",
|
|
22
|
-
"@kevisual/router": "^0.0.
|
|
22
|
+
"@kevisual/router": "^0.0.80",
|
|
23
23
|
"@types/node": "^25.2.3",
|
|
24
24
|
"typescript": "^5.9.3",
|
|
25
25
|
"es-toolkit": "^1.44.0",
|
package/src/adapter.ts
CHANGED
|
@@ -13,14 +13,6 @@ export type AdapterOpts = {
|
|
|
13
13
|
body?: Record<string, any> | FormData; // body 可以是对象、字符串或 FormData
|
|
14
14
|
timeout?: number;
|
|
15
15
|
method?: Method;
|
|
16
|
-
/**
|
|
17
|
-
* @deprecated use responseType
|
|
18
|
-
*/
|
|
19
|
-
isBlob?: boolean; // 是否返回 Blob 对象, 第一优先
|
|
20
|
-
/**
|
|
21
|
-
* @deprecated use responseType
|
|
22
|
-
*/
|
|
23
|
-
isText?: boolean; // 是否返回文本内容, 第二优先
|
|
24
16
|
/**
|
|
25
17
|
* 响应类型,
|
|
26
18
|
* */
|
|
@@ -29,7 +21,7 @@ export type AdapterOpts = {
|
|
|
29
21
|
};
|
|
30
22
|
export const isTextForContentType = (contentType: string | null) => {
|
|
31
23
|
if (!contentType) return false;
|
|
32
|
-
const textTypes = ['text/', 'xml', 'html', 'javascript', 'css', 'csv', 'plain', 'x-www-form-urlencoded', 'md'];
|
|
24
|
+
const textTypes = ['text/', 'xml', 'html', 'javascript', 'css', 'csv', 'plain', 'x-www-form-urlencoded', 'md', 'json'];
|
|
33
25
|
return textTypes.some((type) => contentType.includes(type));
|
|
34
26
|
};
|
|
35
27
|
/**
|
|
@@ -42,13 +34,6 @@ export const adapter = async (opts: AdapterOpts = {}, overloadOpts?: RequestInit
|
|
|
42
34
|
const controller = new AbortController();
|
|
43
35
|
const signal = controller.signal;
|
|
44
36
|
const isPostFile = opts.isPostFile || false; // 是否为文件上传
|
|
45
|
-
let responseType = opts.responseType || 'json'; // 响应类型
|
|
46
|
-
if (opts.isBlob) {
|
|
47
|
-
responseType = 'blob';
|
|
48
|
-
} else if (opts.isText) {
|
|
49
|
-
responseType = 'text';
|
|
50
|
-
}
|
|
51
|
-
|
|
52
37
|
const timeout = opts.timeout || 60000 * 3; // 默认超时时间为 60s * 3
|
|
53
38
|
const timer = setTimeout(() => {
|
|
54
39
|
controller.abort();
|
|
@@ -110,22 +95,32 @@ export const adapter = async (opts: AdapterOpts = {}, overloadOpts?: RequestInit
|
|
|
110
95
|
.then(async (response) => {
|
|
111
96
|
// 获取 Content-Type 头部信息
|
|
112
97
|
const contentType = response.headers.get('Content-Type');
|
|
113
|
-
if (responseType === 'blob') {
|
|
114
|
-
return await response.blob(); // 直接返回 Blob 对象
|
|
115
|
-
}
|
|
116
|
-
const isText = responseType === 'text';
|
|
117
98
|
const isJson = contentType && contentType.includes('application/json');
|
|
99
|
+
const isSuccess = response.ok;
|
|
118
100
|
// 判断返回的数据类型
|
|
119
|
-
if (isJson
|
|
120
|
-
|
|
101
|
+
if (isJson) {
|
|
102
|
+
const json = await response.json();
|
|
103
|
+
if (json?.code) {
|
|
104
|
+
return json;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
code: isSuccess ? 200 : response.status,
|
|
108
|
+
status: response.status,
|
|
109
|
+
data: json,
|
|
110
|
+
}
|
|
121
111
|
} else if (isTextForContentType(contentType)) {
|
|
122
112
|
return {
|
|
123
|
-
code: response.status,
|
|
113
|
+
code: isSuccess ? 200 : response.status,
|
|
124
114
|
status: response.status,
|
|
125
115
|
data: await response.text(), // 直接返回文本内容
|
|
126
116
|
};
|
|
127
117
|
} else {
|
|
128
|
-
return
|
|
118
|
+
return {
|
|
119
|
+
code: isSuccess ? 200 : response.status,
|
|
120
|
+
status: response.status,
|
|
121
|
+
data: '非文本非JSON响应, 请手动处理response。',
|
|
122
|
+
response
|
|
123
|
+
};
|
|
129
124
|
}
|
|
130
125
|
})
|
|
131
126
|
.catch((err) => {
|
|
@@ -143,8 +138,4 @@ export const adapter = async (opts: AdapterOpts = {}, overloadOpts?: RequestInit
|
|
|
143
138
|
.finally(() => {
|
|
144
139
|
clearTimeout(timer);
|
|
145
140
|
});
|
|
146
|
-
};
|
|
147
|
-
/**
|
|
148
|
-
* adapter
|
|
149
|
-
*/
|
|
150
|
-
export const queryFetch = adapter;
|
|
141
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
|
|
2
|
+
import { toJSONSchema, fromJSONSchema } from '@kevisual/router/browser'
|
|
2
3
|
type RouteInfo = {
|
|
3
4
|
path: string;
|
|
4
5
|
key: string;
|
|
@@ -44,6 +45,14 @@ export const createQueryByRoutes = (list: RouteInfo[]) => {
|
|
|
44
45
|
if (!obj[route.path]) {
|
|
45
46
|
obj[route.path] = {};
|
|
46
47
|
}
|
|
48
|
+
if (route.metadata?.args) {
|
|
49
|
+
const args = route.metadata.args;
|
|
50
|
+
if (args?.$schema) {
|
|
51
|
+
// 将 args 转换为 JSON Schema
|
|
52
|
+
const jsonSchema = fromJSONSchema(args);
|
|
53
|
+
route.metadata.args = toJSONSchema(jsonSchema);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
47
56
|
obj[route.path][route.key] = route;
|
|
48
57
|
}
|
|
49
58
|
const code = `
|