@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.
@@ -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, queryFetch };
29
+ export { adapter, isTextForContentType, methods };
42
30
  export type { AdapterOpts, Method };
@@ -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
- if (isJson && !isText) {
83
- return await response.json();
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 response;
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
@@ -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
- * 默认是 /client/router或者 默认是 /api/router
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]>, opts?: DataOpts) => ReturnType<Query['post']>;
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>, opts?: DataOpts): Promise<{
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
- if (isJson && !isText) {
82
- return await response.json();
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 response;
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
- success: false,
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
- isClient = false;
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 = globalThis?.localStorage?.getItem("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: "request is cancel",
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: "api request beforeFn error",
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 > 30) {
208
- console.error("request stop: timeout", req.url, timer);
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("request afterFn error", e, req);
237
+ console.error("请求在响应后处理时发生错误", e, req);
225
238
  return wrapperError({
226
239
  code: 500,
227
- message: "api request afterFn error",
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
@@ -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
- * 默认是 /client/router或者 默认是 /api/router
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 };
@@ -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
- if (isJson && !isText) {
82
- return await response.json();
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 response;
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
- success: false,
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
- isClient = false;
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 = globalThis?.localStorage?.getItem("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: "request is cancel",
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: "api request beforeFn error",
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 > 30) {
405
- console.error("request stop: timeout", req.url, timer);
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("request afterFn error", e, req);
434
+ console.error("请求在响应后处理时发生错误", e, req);
422
435
  return wrapperError({
423
436
  code: 500,
424
- message: "api request afterFn error",
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
- * 默认是 /client/router或者 默认是 /api/router
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, setBaseResponse, wrapperError };
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
- if (isJson && !isText) {
82
- return await response.json();
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 response;
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
- success: false,
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
- isClient = false;
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 = globalThis?.localStorage?.getItem("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: "request is cancel",
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: "api request beforeFn error",
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 > 30) {
217
- console.error("request stop: timeout", req.url, timer);
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("request afterFn error", e, req);
237
+ console.error("请求在响应后处理时发生错误", e, req);
234
238
  return wrapperError({
235
239
  code: 500,
236
- message: "api request afterFn error",
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.45",
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.74",
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 && !isText) {
120
- return await response.json(); // 解析为 JSON
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 response;
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>, opts?: DataOpts) => {
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
@@ -19,23 +19,8 @@ type QueryOpts = {
19
19
  * 前端调用后端QueryRouter, 封装 beforeRequest 和 wss
20
20
  */
21
21
  export class QueryClient extends Query {
22
- tokenName: string;
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
- success: false,
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
- * 默认是 /client/router或者 默认是 /api/router
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 = globalThis?.localStorage?.getItem('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: 'request is cancel',
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: 'api request beforeFn error',
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 > 30) {
211
- console.error('request stop: timeout', req.url, timer);
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('request afterFn error', e, req);
217
+ console.error('请求在响应后处理时发生错误', e, req);
229
218
  return wrapperError({
230
219
  code: 500,
231
- message: 'api request afterFn error',
220
+ message: '请求在响应后处理时发生错误',
232
221
  // @ts-ignore
233
222
  req: req,
234
223
  });