@kevisual/query 0.0.45 → 0.0.47
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 +7 -14
- package/dist/query-api.js +46 -30
- 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/query-api.ts +6 -3
- package/src/query-browser.ts +1 -25
- package/src/query.ts +27 -38
package/dist/query-adapter.d.ts
CHANGED
|
@@ -11,14 +11,6 @@ type AdapterOpts = {
|
|
|
11
11
|
body?: Record<string, any> | FormData;
|
|
12
12
|
timeout?: number;
|
|
13
13
|
method?: Method;
|
|
14
|
-
/**
|
|
15
|
-
* @deprecated use responseType
|
|
16
|
-
*/
|
|
17
|
-
isBlob?: boolean;
|
|
18
|
-
/**
|
|
19
|
-
* @deprecated use responseType
|
|
20
|
-
*/
|
|
21
|
-
isText?: boolean;
|
|
22
14
|
/**
|
|
23
15
|
* 响应类型,
|
|
24
16
|
* */
|
|
@@ -33,10 +25,6 @@ declare const isTextForContentType: (contentType: string | null) => boolean;
|
|
|
33
25
|
* @returns
|
|
34
26
|
*/
|
|
35
27
|
declare const adapter: (opts?: AdapterOpts, overloadOpts?: RequestInit) => Promise<any>;
|
|
36
|
-
/**
|
|
37
|
-
* adapter
|
|
38
|
-
*/
|
|
39
|
-
declare const queryFetch: (opts?: AdapterOpts, overloadOpts?: RequestInit) => Promise<any>;
|
|
40
28
|
|
|
41
|
-
export { adapter, isTextForContentType, methods
|
|
29
|
+
export { adapter, isTextForContentType, methods };
|
|
42
30
|
export type { AdapterOpts, Method };
|
package/dist/query-adapter.js
CHANGED
|
@@ -3,19 +3,13 @@ var methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"];
|
|
|
3
3
|
var isTextForContentType = (contentType) => {
|
|
4
4
|
if (!contentType)
|
|
5
5
|
return false;
|
|
6
|
-
const textTypes = ["text/", "xml", "html", "javascript", "css", "csv", "plain", "x-www-form-urlencoded", "md"];
|
|
6
|
+
const textTypes = ["text/", "xml", "html", "javascript", "css", "csv", "plain", "x-www-form-urlencoded", "md", "json"];
|
|
7
7
|
return textTypes.some((type) => contentType.includes(type));
|
|
8
8
|
};
|
|
9
9
|
var adapter = async (opts = {}, overloadOpts) => {
|
|
10
10
|
const controller = new AbortController;
|
|
11
11
|
const signal = controller.signal;
|
|
12
12
|
const isPostFile = opts.isPostFile || false;
|
|
13
|
-
let responseType = opts.responseType || "json";
|
|
14
|
-
if (opts.isBlob) {
|
|
15
|
-
responseType = "blob";
|
|
16
|
-
} else if (opts.isText) {
|
|
17
|
-
responseType = "text";
|
|
18
|
-
}
|
|
19
13
|
const timeout = opts.timeout || 60000 * 3;
|
|
20
14
|
const timer = setTimeout(() => {
|
|
21
15
|
controller.abort();
|
|
@@ -74,21 +68,31 @@ var adapter = async (opts = {}, overloadOpts) => {
|
|
|
74
68
|
headers
|
|
75
69
|
}).then(async (response) => {
|
|
76
70
|
const contentType = response.headers.get("Content-Type");
|
|
77
|
-
if (responseType === "blob") {
|
|
78
|
-
return await response.blob();
|
|
79
|
-
}
|
|
80
|
-
const isText = responseType === "text";
|
|
81
71
|
const isJson = contentType && contentType.includes("application/json");
|
|
82
|
-
|
|
83
|
-
|
|
72
|
+
const isSuccess = response.ok;
|
|
73
|
+
if (isJson) {
|
|
74
|
+
const json = await response.json();
|
|
75
|
+
if (json?.code) {
|
|
76
|
+
return json;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
code: isSuccess ? 200 : response.status,
|
|
80
|
+
status: response.status,
|
|
81
|
+
data: json
|
|
82
|
+
};
|
|
84
83
|
} else if (isTextForContentType(contentType)) {
|
|
85
84
|
return {
|
|
86
|
-
code: response.status,
|
|
85
|
+
code: isSuccess ? 200 : response.status,
|
|
87
86
|
status: response.status,
|
|
88
87
|
data: await response.text()
|
|
89
88
|
};
|
|
90
89
|
} else {
|
|
91
|
-
return
|
|
90
|
+
return {
|
|
91
|
+
code: isSuccess ? 200 : response.status,
|
|
92
|
+
status: response.status,
|
|
93
|
+
data: "非文本非JSON响应, 请手动处理response。",
|
|
94
|
+
response
|
|
95
|
+
};
|
|
92
96
|
}
|
|
93
97
|
}).catch((err) => {
|
|
94
98
|
if (err.name === "AbortError") {
|
|
@@ -105,9 +109,7 @@ var adapter = async (opts = {}, overloadOpts) => {
|
|
|
105
109
|
clearTimeout(timer);
|
|
106
110
|
});
|
|
107
111
|
};
|
|
108
|
-
var queryFetch = adapter;
|
|
109
112
|
export {
|
|
110
|
-
queryFetch,
|
|
111
113
|
methods,
|
|
112
114
|
isTextForContentType,
|
|
113
115
|
adapter
|
package/dist/query-api.d.ts
CHANGED
|
@@ -14,14 +14,6 @@ type AdapterOpts = {
|
|
|
14
14
|
body?: Record<string, any> | FormData;
|
|
15
15
|
timeout?: number;
|
|
16
16
|
method?: Method;
|
|
17
|
-
/**
|
|
18
|
-
* @deprecated use responseType
|
|
19
|
-
*/
|
|
20
|
-
isBlob?: boolean;
|
|
21
|
-
/**
|
|
22
|
-
* @deprecated use responseType
|
|
23
|
-
*/
|
|
24
|
-
isText?: boolean;
|
|
25
17
|
/**
|
|
26
18
|
* 响应类型,
|
|
27
19
|
* */
|
|
@@ -119,6 +111,8 @@ type QueryOptions = {
|
|
|
119
111
|
headers?: Record<string, string>;
|
|
120
112
|
timeout?: number;
|
|
121
113
|
isClient?: boolean;
|
|
114
|
+
tokenName?: string;
|
|
115
|
+
storage?: Storage;
|
|
122
116
|
beforeRequest?: Fn;
|
|
123
117
|
};
|
|
124
118
|
type Data = {
|
|
@@ -171,10 +165,9 @@ declare class Query {
|
|
|
171
165
|
*/
|
|
172
166
|
stop?: boolean;
|
|
173
167
|
qws: QueryWs;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
isClient: boolean;
|
|
168
|
+
tokenName: string;
|
|
169
|
+
storage: Storage;
|
|
170
|
+
token: string;
|
|
178
171
|
constructor(opts?: QueryOptions);
|
|
179
172
|
setQueryWs(qws: QueryWs): void;
|
|
180
173
|
/**
|
|
@@ -311,7 +304,7 @@ type ApiMethods<P extends {
|
|
|
311
304
|
};
|
|
312
305
|
}> = {
|
|
313
306
|
[Path in keyof P]: {
|
|
314
|
-
[Key in keyof P[Path]]: (data?: ExtractArgsFromMetadata<P[Path][Key]
|
|
307
|
+
[Key in keyof P[Path]]: (data?: Partial<ExtractArgsFromMetadata<P[Path][Key]>>, opts?: DataOpts) => ReturnType<Query['post']>;
|
|
315
308
|
};
|
|
316
309
|
};
|
|
317
310
|
type QueryApiOpts<P extends {
|
|
@@ -329,7 +322,7 @@ declare class QueryApi<P extends {
|
|
|
329
322
|
} = {}> {
|
|
330
323
|
query: Query;
|
|
331
324
|
constructor(opts?: QueryApiOpts<P>);
|
|
332
|
-
post<T extends Pos>(pos: T, data?: ExtractArgsFromMetadata<T
|
|
325
|
+
post<T extends Pos>(pos: T, data?: Partial<ExtractArgsFromMetadata<T>>, opts?: DataOpts): Promise<{
|
|
333
326
|
code: number;
|
|
334
327
|
data?: any;
|
|
335
328
|
message?: string;
|
package/dist/query-api.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") {
|
|
@@ -109,10 +113,7 @@ var adapter = async (opts = {}, overloadOpts) => {
|
|
|
109
113
|
var wrapperError = ({ code, message }) => {
|
|
110
114
|
const result = {
|
|
111
115
|
code: code || 500,
|
|
112
|
-
|
|
113
|
-
message: message || "api request error",
|
|
114
|
-
showError: (fn) => {},
|
|
115
|
-
noMsg: true
|
|
116
|
+
message: message || "请求错误"
|
|
116
117
|
};
|
|
117
118
|
return result;
|
|
118
119
|
};
|
|
@@ -126,9 +127,13 @@ class Query {
|
|
|
126
127
|
timeout;
|
|
127
128
|
stop;
|
|
128
129
|
qws;
|
|
129
|
-
|
|
130
|
+
tokenName;
|
|
131
|
+
storage;
|
|
132
|
+
token;
|
|
130
133
|
constructor(opts) {
|
|
131
134
|
this.adapter = opts?.adapter || adapter;
|
|
135
|
+
this.tokenName = opts?.tokenName || "token";
|
|
136
|
+
this.storage = opts?.storage || globalThis?.localStorage;
|
|
132
137
|
const defaultURL = opts?.isClient ? "/client/router" : "/api/router";
|
|
133
138
|
this.url = opts?.url || defaultURL;
|
|
134
139
|
this.headers = opts?.headers || {
|
|
@@ -139,7 +144,7 @@ class Query {
|
|
|
139
144
|
this.beforeRequest = opts.beforeRequest;
|
|
140
145
|
} else {
|
|
141
146
|
this.beforeRequest = async (opts2) => {
|
|
142
|
-
const token =
|
|
147
|
+
const token = this.token || this.storage?.getItem?.(this.tokenName);
|
|
143
148
|
if (token) {
|
|
144
149
|
opts2.headers = {
|
|
145
150
|
...opts2.headers,
|
|
@@ -161,7 +166,6 @@ class Query {
|
|
|
161
166
|
}
|
|
162
167
|
async post(body, options) {
|
|
163
168
|
const url = options?.url || this.url;
|
|
164
|
-
console.log("query post", url, body, options);
|
|
165
169
|
const { headers, adapter: adapter2, beforeRequest, afterResponse, timeout, ...rest } = options || {};
|
|
166
170
|
const _headers = { ...this.headers, ...headers };
|
|
167
171
|
const _adapter = adapter2 || this.adapter;
|
|
@@ -181,7 +185,7 @@ class Query {
|
|
|
181
185
|
if (res === false) {
|
|
182
186
|
return wrapperError({
|
|
183
187
|
code: 500,
|
|
184
|
-
message: "
|
|
188
|
+
message: "请求取消",
|
|
185
189
|
req
|
|
186
190
|
});
|
|
187
191
|
}
|
|
@@ -190,13 +194,13 @@ class Query {
|
|
|
190
194
|
console.error("request beforeFn error", e, req);
|
|
191
195
|
return wrapperError({
|
|
192
196
|
code: 500,
|
|
193
|
-
message: "
|
|
197
|
+
message: "请求在请求前处理时发生错误",
|
|
194
198
|
req
|
|
195
199
|
});
|
|
196
200
|
}
|
|
197
201
|
if (this.stop && !options?.noStop) {
|
|
198
202
|
const that = this;
|
|
199
|
-
await new Promise((resolve) => {
|
|
203
|
+
const res = await new Promise((resolve) => {
|
|
200
204
|
let timer = 0;
|
|
201
205
|
const detect = setInterval(() => {
|
|
202
206
|
if (!that.stop) {
|
|
@@ -204,11 +208,20 @@ class Query {
|
|
|
204
208
|
resolve(true);
|
|
205
209
|
}
|
|
206
210
|
timer++;
|
|
207
|
-
if (timer >
|
|
208
|
-
console.error("
|
|
211
|
+
if (timer > 5) {
|
|
212
|
+
console.error("等待请求失败:", req.url, timer);
|
|
213
|
+
clearInterval(detect);
|
|
214
|
+
resolve(false);
|
|
209
215
|
}
|
|
210
216
|
}, 1000);
|
|
211
217
|
});
|
|
218
|
+
if (!res) {
|
|
219
|
+
return wrapperError({
|
|
220
|
+
code: 500,
|
|
221
|
+
message: "请求取消,可能是因为用户未登录或者token过期",
|
|
222
|
+
req
|
|
223
|
+
});
|
|
224
|
+
}
|
|
212
225
|
}
|
|
213
226
|
return _adapter(req).then(async (res) => {
|
|
214
227
|
try {
|
|
@@ -221,10 +234,10 @@ class Query {
|
|
|
221
234
|
}
|
|
222
235
|
return res;
|
|
223
236
|
} catch (e) {
|
|
224
|
-
console.error("
|
|
237
|
+
console.error("请求在响应后处理时发生错误", e, req);
|
|
225
238
|
return wrapperError({
|
|
226
239
|
code: 500,
|
|
227
|
-
message: "
|
|
240
|
+
message: "请求在响应后处理时发生错误",
|
|
228
241
|
req
|
|
229
242
|
});
|
|
230
243
|
}
|
|
@@ -428,8 +441,11 @@ class QueryApi {
|
|
|
428
441
|
that[path] = {};
|
|
429
442
|
}
|
|
430
443
|
for (const [key, pos] of Object.entries(methods)) {
|
|
431
|
-
that[path][key] = (data, opts) => {
|
|
444
|
+
that[path][key] = (data, opts = {}) => {
|
|
432
445
|
const _pos = pick(pos, ["path", "key", "id"]);
|
|
446
|
+
if (pos.metadata?.viewItem?.api?.url && !opts.url) {
|
|
447
|
+
opts.url = pos.metadata.viewItem.api.url;
|
|
448
|
+
}
|
|
433
449
|
return that.query.post({
|
|
434
450
|
..._pos,
|
|
435
451
|
payload: data
|
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.47",
|
|
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.75",
|
|
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
|
+
};
|
package/src/query-api.ts
CHANGED
|
@@ -75,7 +75,7 @@ type ExtractArgsFromMetadata<T> = T extends { metadata?: { args?: infer A } }
|
|
|
75
75
|
type ApiMethods<P extends { [path: string]: { [key: string]: Pos } }> = {
|
|
76
76
|
[Path in keyof P]: {
|
|
77
77
|
[Key in keyof P[Path]]: (
|
|
78
|
-
data?: ExtractArgsFromMetadata<P[Path][Key]
|
|
78
|
+
data?: Partial<ExtractArgsFromMetadata<P[Path][Key]>>,
|
|
79
79
|
opts?: DataOpts
|
|
80
80
|
) => ReturnType<Query['post']>
|
|
81
81
|
}
|
|
@@ -97,7 +97,7 @@ export class QueryApi<P extends { [path: string]: { [key: string]: Pos } } = {}>
|
|
|
97
97
|
// 使用泛型来推断类型
|
|
98
98
|
post<T extends Pos>(
|
|
99
99
|
pos: T,
|
|
100
|
-
data?: ExtractArgsFromMetadata<T
|
|
100
|
+
data?: Partial<ExtractArgsFromMetadata<T>>,
|
|
101
101
|
opts?: DataOpts
|
|
102
102
|
) {
|
|
103
103
|
const _pos = pick(pos, ['path', 'key', 'id']);
|
|
@@ -121,8 +121,11 @@ export class QueryApi<P extends { [path: string]: { [key: string]: Pos } } = {}>
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
for (const [key, pos] of Object.entries(methods)) {
|
|
124
|
-
that[path][key] = (data?: ExtractArgsFromMetadata<typeof pos
|
|
124
|
+
that[path][key] = (data?: Partial<ExtractArgsFromMetadata<typeof pos>>, opts: DataOpts = {}) => {
|
|
125
125
|
const _pos = pick(pos, ['path', 'key', 'id']);
|
|
126
|
+
if (pos.metadata?.viewItem?.api?.url && !opts.url) {
|
|
127
|
+
opts.url = pos.metadata.viewItem.api.url;
|
|
128
|
+
}
|
|
126
129
|
return that.query.post({
|
|
127
130
|
..._pos,
|
|
128
131
|
payload: data
|
package/src/query-browser.ts
CHANGED
|
@@ -19,23 +19,8 @@ type QueryOpts = {
|
|
|
19
19
|
* 前端调用后端QueryRouter, 封装 beforeRequest 和 wss
|
|
20
20
|
*/
|
|
21
21
|
export class QueryClient extends Query {
|
|
22
|
-
|
|
23
|
-
storage: Storage;
|
|
24
|
-
token: string;
|
|
25
|
-
constructor(opts?: QueryOptions & { tokenName?: string; storage?: Storage; io?: boolean }) {
|
|
22
|
+
constructor(opts?: QueryOptions & { io?: boolean }) {
|
|
26
23
|
super(opts);
|
|
27
|
-
this.tokenName = opts?.tokenName || 'token';
|
|
28
|
-
this.storage = opts?.storage || globalThis.localStorage;
|
|
29
|
-
this.beforeRequest = async (opts) => {
|
|
30
|
-
const token = this.token || this.getToken();
|
|
31
|
-
if (token) {
|
|
32
|
-
opts.headers = {
|
|
33
|
-
...opts.headers,
|
|
34
|
-
Authorization: `Bearer ${token}`,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
return opts;
|
|
38
|
-
};
|
|
39
24
|
if (opts?.io) {
|
|
40
25
|
this.createWs();
|
|
41
26
|
}
|
|
@@ -43,15 +28,6 @@ export class QueryClient extends Query {
|
|
|
43
28
|
createWs(opts?: QueryWsOpts) {
|
|
44
29
|
this.qws = new QueryWs({ url: this.url, ...opts });
|
|
45
30
|
}
|
|
46
|
-
getToken() {
|
|
47
|
-
return this.storage.getItem(this.tokenName);
|
|
48
|
-
}
|
|
49
|
-
saveToken(token: string) {
|
|
50
|
-
this.storage.setItem(this.tokenName, token);
|
|
51
|
-
}
|
|
52
|
-
removeToken() {
|
|
53
|
-
this.storage.removeItem(this.tokenName);
|
|
54
|
-
}
|
|
55
31
|
}
|
|
56
32
|
// 移除默认生成的实例
|
|
57
33
|
// export const client = new QueryClient();
|
package/src/query.ts
CHANGED
|
@@ -24,6 +24,8 @@ export type QueryOptions = {
|
|
|
24
24
|
headers?: Record<string, string>;
|
|
25
25
|
timeout?: number;
|
|
26
26
|
isClient?: boolean;
|
|
27
|
+
tokenName?: string;
|
|
28
|
+
storage?: Storage;
|
|
27
29
|
beforeRequest?: Fn;
|
|
28
30
|
}
|
|
29
31
|
export type Data = {
|
|
@@ -46,34 +48,11 @@ export type DataOpts = Partial<QueryOpts> & {
|
|
|
46
48
|
*/
|
|
47
49
|
noStop?: boolean;
|
|
48
50
|
};
|
|
49
|
-
|
|
50
|
-
* 设置基础响应, 设置 success 和 showError,
|
|
51
|
-
* success 是 code 是否等于 200
|
|
52
|
-
* showError 是 如果 success 为 false 且 noMsg 为 false, 则调用 showError
|
|
53
|
-
* @param res 响应
|
|
54
|
-
*/
|
|
55
|
-
export const setBaseResponse = (res: Partial<Result & { success?: boolean; showError?: (fn?: () => void) => void; noMsg?: boolean }>) => {
|
|
56
|
-
res.success = res.code === 200;
|
|
57
|
-
/**
|
|
58
|
-
* 显示错误
|
|
59
|
-
* @param fn 错误处理函数
|
|
60
|
-
*/
|
|
61
|
-
res.showError = (fn?: () => void) => {
|
|
62
|
-
if (!res.success && !res.noMsg) {
|
|
63
|
-
fn?.();
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
return res as Result;
|
|
67
|
-
};
|
|
51
|
+
|
|
68
52
|
export const wrapperError = ({ code, message }: { code?: number; message?: string }) => {
|
|
69
53
|
const result = {
|
|
70
54
|
code: code || 500,
|
|
71
|
-
|
|
72
|
-
message: message || 'api request error',
|
|
73
|
-
showError: (fn?: () => void) => {
|
|
74
|
-
//
|
|
75
|
-
},
|
|
76
|
-
noMsg: true,
|
|
55
|
+
message: message || '请求错误'
|
|
77
56
|
};
|
|
78
57
|
return result;
|
|
79
58
|
};
|
|
@@ -105,12 +84,13 @@ export class Query {
|
|
|
105
84
|
stop?: boolean;
|
|
106
85
|
// 默认不使用ws
|
|
107
86
|
qws: QueryWs;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
isClient = false;
|
|
87
|
+
tokenName: string;
|
|
88
|
+
storage: Storage;
|
|
89
|
+
token: string;
|
|
112
90
|
constructor(opts?: QueryOptions) {
|
|
113
91
|
this.adapter = opts?.adapter || adapter;
|
|
92
|
+
this.tokenName = opts?.tokenName || 'token';
|
|
93
|
+
this.storage = opts?.storage || globalThis?.localStorage;
|
|
114
94
|
const defaultURL = opts?.isClient ? '/client/router' : '/api/router';
|
|
115
95
|
this.url = opts?.url || defaultURL;
|
|
116
96
|
this.headers = opts?.headers || {
|
|
@@ -121,7 +101,7 @@ export class Query {
|
|
|
121
101
|
this.beforeRequest = opts.beforeRequest;
|
|
122
102
|
} else {
|
|
123
103
|
this.beforeRequest = async (opts) => {
|
|
124
|
-
const token =
|
|
104
|
+
const token = this.token || this.storage?.getItem?.(this.tokenName);
|
|
125
105
|
if (token) {
|
|
126
106
|
opts.headers = {
|
|
127
107
|
...opts.headers,
|
|
@@ -162,7 +142,6 @@ export class Query {
|
|
|
162
142
|
*/
|
|
163
143
|
async post<R = any, P = any>(body: Data & P, options?: DataOpts): Promise<Result<R>> {
|
|
164
144
|
const url = options?.url || this.url;
|
|
165
|
-
console.log('query post', url, body, options);
|
|
166
145
|
const { headers, adapter, beforeRequest, afterResponse, timeout, ...rest } = options || {};
|
|
167
146
|
const _headers = { ...this.headers, ...headers };
|
|
168
147
|
const _adapter = adapter || this.adapter;
|
|
@@ -182,7 +161,7 @@ export class Query {
|
|
|
182
161
|
if (res === false) {
|
|
183
162
|
return wrapperError({
|
|
184
163
|
code: 500,
|
|
185
|
-
message: '
|
|
164
|
+
message: '请求取消',
|
|
186
165
|
// @ts-ignore
|
|
187
166
|
req: req,
|
|
188
167
|
});
|
|
@@ -192,14 +171,14 @@ export class Query {
|
|
|
192
171
|
console.error('request beforeFn error', e, req);
|
|
193
172
|
return wrapperError({
|
|
194
173
|
code: 500,
|
|
195
|
-
message: '
|
|
174
|
+
message: '请求在请求前处理时发生错误',
|
|
196
175
|
// @ts-ignore
|
|
197
176
|
req: req,
|
|
198
177
|
});
|
|
199
178
|
}
|
|
200
179
|
if (this.stop && !options?.noStop) {
|
|
201
180
|
const that = this;
|
|
202
|
-
await new Promise((resolve) => {
|
|
181
|
+
const res = await new Promise((resolve) => {
|
|
203
182
|
let timer = 0;
|
|
204
183
|
const detect = setInterval(() => {
|
|
205
184
|
if (!that.stop) {
|
|
@@ -207,11 +186,21 @@ export class Query {
|
|
|
207
186
|
resolve(true);
|
|
208
187
|
}
|
|
209
188
|
timer++;
|
|
210
|
-
if (timer >
|
|
211
|
-
console.error('
|
|
189
|
+
if (timer > 5) {
|
|
190
|
+
console.error('等待请求失败:', req.url, timer);
|
|
191
|
+
clearInterval(detect);
|
|
192
|
+
resolve(false);
|
|
212
193
|
}
|
|
213
194
|
}, 1000);
|
|
214
195
|
});
|
|
196
|
+
if (!res) {
|
|
197
|
+
return wrapperError({
|
|
198
|
+
code: 500,
|
|
199
|
+
message: '请求取消,可能是因为用户未登录或者token过期',
|
|
200
|
+
// @ts-ignore
|
|
201
|
+
req: req,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
215
204
|
}
|
|
216
205
|
return _adapter(req).then(async (res) => {
|
|
217
206
|
try {
|
|
@@ -225,10 +214,10 @@ export class Query {
|
|
|
225
214
|
|
|
226
215
|
return res;
|
|
227
216
|
} catch (e) {
|
|
228
|
-
console.error('
|
|
217
|
+
console.error('请求在响应后处理时发生错误', e, req);
|
|
229
218
|
return wrapperError({
|
|
230
219
|
code: 500,
|
|
231
|
-
message: '
|
|
220
|
+
message: '请求在响应后处理时发生错误',
|
|
232
221
|
// @ts-ignore
|
|
233
222
|
req: req,
|
|
234
223
|
});
|