@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/src/query-api.ts CHANGED
@@ -64,18 +64,27 @@ type InferType<T> =
64
64
  T extends { properties: infer P } ? InferFromJSONSchema<T> : // 处理没有 type 但有 properties 的对象
65
65
  T;
66
66
 
67
+ // 检查是否标记为可选
68
+ type IsOptional<T> = T extends { optional: true } ? true : false;
69
+
67
70
  // 提取 args 对象,将每个 Zod schema 或 JSON Schema 转换为实际类型
71
+ // 根据 optional 字段分离必需字段和可选字段
68
72
  type ExtractArgsFromMetadata<T> = T extends { metadata?: { args?: infer A } }
69
73
  ? A extends Record<string, any>
70
- ? { [K in keyof A]: InferType<A[K]> }
71
- : never
74
+ ? (
75
+ // 必需字段(没有 optional: true)
76
+ { [K in keyof A as IsOptional<A[K]> extends true ? never : K]: InferType<A[K]> } &
77
+ // 可选字段(有 optional: true)
78
+ { [K in keyof A as IsOptional<A[K]> extends true ? K : never]?: InferType<A[K]> }
79
+ )
80
+ : never
72
81
  : never;
73
82
 
74
83
  // 类型映射:将 API 配置转换为方法签名
75
84
  type ApiMethods<P extends { [path: string]: { [key: string]: Pos } }> = {
76
85
  [Path in keyof P]: {
77
86
  [Key in keyof P[Path]]: (
78
- data?: Partial<ExtractArgsFromMetadata<P[Path][Key]>>,
87
+ data?: ExtractArgsFromMetadata<P[Path][Key]>,
79
88
  opts?: DataOpts
80
89
  ) => ReturnType<Query['post']>
81
90
  }
@@ -97,7 +106,7 @@ export class QueryApi<P extends { [path: string]: { [key: string]: Pos } } = {}>
97
106
  // 使用泛型来推断类型
98
107
  post<T extends Pos>(
99
108
  pos: T,
100
- data?: Partial<ExtractArgsFromMetadata<T>>,
109
+ data?: ExtractArgsFromMetadata<T>,
101
110
  opts?: DataOpts
102
111
  ) {
103
112
  const _pos = pick(pos, ['path', 'key', 'id']);
@@ -121,8 +130,11 @@ export class QueryApi<P extends { [path: string]: { [key: string]: Pos } } = {}>
121
130
  }
122
131
 
123
132
  for (const [key, pos] of Object.entries(methods)) {
124
- that[path][key] = (data?: Partial<ExtractArgsFromMetadata<typeof pos>>, opts?: DataOpts) => {
133
+ that[path][key] = (data?: ExtractArgsFromMetadata<typeof pos>, opts: DataOpts = {}) => {
125
134
  const _pos = pick(pos, ['path', 'key', 'id']);
135
+ if (pos.metadata?.viewItem?.api?.url && !opts.url) {
136
+ opts.url = pos.metadata.viewItem.api.url;
137
+ }
126
138
  return that.query.post({
127
139
  ..._pos,
128
140
  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
  });