@kevisual/query 0.0.13 → 0.0.15

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.
@@ -1,8 +1,11 @@
1
+ declare const methods: readonly ["GET", "POST"];
2
+ type Method = (typeof methods)[number];
1
3
  type AdapterOpts = {
2
4
  url: string;
3
5
  headers?: Record<string, string>;
4
6
  body?: Record<string, any>;
5
7
  timeout?: number;
8
+ method?: Method;
6
9
  };
7
10
  /**
8
11
  *
@@ -16,4 +19,5 @@ declare const adapter: (opts: AdapterOpts, overloadOpts?: RequestInit) => Promis
16
19
  */
17
20
  declare const queryFetch: (opts: AdapterOpts, overloadOpts?: RequestInit) => Promise<any>;
18
21
 
19
- export { adapter, queryFetch };
22
+ export { adapter, methods, queryFetch };
23
+ export type { AdapterOpts, Method };
@@ -1,3 +1,4 @@
1
+ const methods = ['GET', 'POST'];
1
2
  /**
2
3
  *
3
4
  * @param opts
@@ -11,15 +12,29 @@ const adapter = async (opts, overloadOpts) => {
11
12
  const timer = setTimeout(() => {
12
13
  controller.abort();
13
14
  }, timeout);
14
- return fetch(opts.url, {
15
- method: 'POST',
15
+ let method = overloadOpts?.method || opts.method || 'POST';
16
+ let origin = '';
17
+ let url;
18
+ if (opts?.url?.startsWith('http')) {
19
+ url = new URL(opts.url);
20
+ }
21
+ else {
22
+ origin = window?.location?.origin || 'http://localhost:11015';
23
+ url = new URL(opts.url, origin);
24
+ }
25
+ const isGet = method === 'GET';
26
+ if (isGet) {
27
+ url.search = new URLSearchParams(opts.body).toString();
28
+ }
29
+ return fetch(url, {
30
+ method: method.toUpperCase(),
16
31
  headers: {
17
32
  'Content-Type': 'application/json',
18
33
  ...opts.headers,
19
34
  },
20
- body: JSON.stringify(opts.body),
21
35
  signal,
22
36
  ...overloadOpts,
37
+ body: isGet ? undefined : JSON.stringify(opts.body),
23
38
  })
24
39
  .then((response) => {
25
40
  // 获取 Content-Type 头部信息
@@ -50,4 +65,4 @@ const adapter = async (opts, overloadOpts) => {
50
65
  */
51
66
  const queryFetch = adapter;
52
67
 
53
- export { adapter, queryFetch };
68
+ export { adapter, methods, queryFetch };
@@ -1,10 +1,13 @@
1
1
  import { StoreApi } from 'zustand/vanilla';
2
2
 
3
+ declare const methods: readonly ["GET", "POST"];
4
+ type Method = (typeof methods)[number];
3
5
  type AdapterOpts = {
4
6
  url: string;
5
7
  headers?: Record<string, string>;
6
8
  body?: Record<string, any>;
7
9
  timeout?: number;
10
+ method?: Method;
8
11
  };
9
12
  /**
10
13
  *
@@ -37,14 +40,39 @@ declare class QueryWs {
37
40
  connect(opts?: {
38
41
  timeout?: number;
39
42
  }): Promise<unknown>;
43
+ /**
44
+ * ws.onopen 必须用这个去获取,否者会丢失链接信息
45
+ * @param callback
46
+ * @returns
47
+ */
40
48
  listenConnect(callback: () => void): () => void;
49
+ listenClose(callback: () => void): () => void;
41
50
  onMessage<T = any, U = any>(fn: (data: U, event: MessageEvent) => void, opts?: {
51
+ /**
52
+ * 是否将数据转换为 JSON
53
+ */
42
54
  isJson?: boolean;
55
+ /**
56
+ * 选择器
57
+ */
43
58
  selector?: (data: T) => U;
44
59
  }): () => void;
45
60
  close(): void;
61
+ /**
62
+ * 发送消息
63
+ *
64
+ * @param data
65
+ * @param opts
66
+ * @returns
67
+ */
46
68
  send<T = any, U = any>(data: T, opts?: {
69
+ /**
70
+ * 是否将数据转换为 JSON
71
+ */
47
72
  isJson?: boolean;
73
+ /**
74
+ * 包装数据
75
+ */
48
76
  wrapper?: (data: T) => U;
49
77
  }): void;
50
78
  getOpen(): boolean;
@@ -67,6 +95,8 @@ type QueryOpts$1 = {
67
95
  adapter?: typeof adapter;
68
96
  headers?: Record<string, string>;
69
97
  timeout?: number;
98
+ method?: Method;
99
+ [key: string]: any;
70
100
  };
71
101
  type Data = {
72
102
  path?: string;
@@ -93,11 +123,11 @@ type Result<S = any> = {
93
123
  };
94
124
  type DataOpts = Partial<QueryOpts$1> & {
95
125
  beforeRequest?: Fn;
96
- afterResponse?: <S, U = S>(result: Result<S>, ctx?: {
126
+ afterResponse?: <S = any>(result: Result<S>, ctx?: {
97
127
  req?: any;
98
128
  res?: any;
99
129
  fetch?: any;
100
- }) => Promise<U>;
130
+ }) => Promise<Result<S>>;
101
131
  };
102
132
  /**
103
133
  * const query = new Query();
@@ -111,7 +141,7 @@ type DataOpts = Partial<QueryOpts$1> & {
111
141
  declare class Query {
112
142
  adapter: typeof adapter;
113
143
  url: string;
114
- beforeRequest?: Fn;
144
+ beforeRequest?: DataOpts['beforeRequest'];
115
145
  afterResponse?: DataOpts['afterResponse'];
116
146
  headers?: Record<string, string>;
117
147
  timeout?: number;
@@ -146,12 +176,12 @@ declare class Query {
146
176
  * 请求前处理,设置请求前处理函数
147
177
  * @param fn 处理函数
148
178
  */
149
- before(fn: Fn): void;
179
+ before(fn: DataOpts['beforeRequest']): void;
150
180
  /**
151
181
  * 请求后处理,设置请求后处理函数
152
182
  * @param fn 处理函数
153
183
  */
154
- after(fn: (result: Result, req?: any) => Promise<any>): void;
184
+ after(fn: DataOpts['afterResponse']): void;
155
185
  }
156
186
 
157
187
  type QueryOpts = {
@@ -11,15 +11,29 @@ const adapter = async (opts, overloadOpts) => {
11
11
  const timer = setTimeout(() => {
12
12
  controller.abort();
13
13
  }, timeout);
14
- return fetch(opts.url, {
15
- method: 'POST',
14
+ let method = overloadOpts?.method || opts.method || 'POST';
15
+ let origin = '';
16
+ let url;
17
+ if (opts?.url?.startsWith('http')) {
18
+ url = new URL(opts.url);
19
+ }
20
+ else {
21
+ origin = window?.location?.origin || 'http://localhost:11015';
22
+ url = new URL(opts.url, origin);
23
+ }
24
+ const isGet = method === 'GET';
25
+ if (isGet) {
26
+ url.search = new URLSearchParams(opts.body).toString();
27
+ }
28
+ return fetch(url, {
29
+ method: method.toUpperCase(),
16
30
  headers: {
17
31
  'Content-Type': 'application/json',
18
32
  ...opts.headers,
19
33
  },
20
- body: JSON.stringify(opts.body),
21
34
  signal,
22
35
  ...overloadOpts,
36
+ body: isGet ? undefined : JSON.stringify(opts.body),
23
37
  })
24
38
  .then((response) => {
25
39
  // 获取 Content-Type 头部信息
@@ -118,30 +132,42 @@ class QueryWs {
118
132
  */
119
133
  async connect(opts) {
120
134
  const store = this.store;
135
+ const that = this;
121
136
  const connected = store.getState().connected;
122
137
  if (connected) {
123
138
  return Promise.resolve(true);
124
139
  }
125
140
  return new Promise((resolve, reject) => {
126
- const ws = this.ws || new WebSocket(this.url);
127
- const timeout = opts?.timeout || 5 * 60 * 1000; // 默认 2 分钟
141
+ const ws = that.ws || new WebSocket(that.url);
142
+ const timeout = opts?.timeout || 5 * 60 * 1000; // 默认 5 分钟
128
143
  let timer = setTimeout(() => {
144
+ const isOpen = ws.readyState === WebSocket.OPEN;
145
+ if (isOpen) {
146
+ console.log('WebSocket 连接成功 in timer');
147
+ resolve(true);
148
+ return;
149
+ }
129
150
  console.error('WebSocket 连接超时');
130
151
  reject('timeout');
131
152
  }, timeout);
132
- ws.onopen = () => {
153
+ ws.onopen = (ev) => {
133
154
  store.getState().setConnected(true);
134
155
  store.getState().setStatus('connected');
135
156
  resolve(true);
136
157
  clearTimeout(timer);
137
158
  };
138
- ws.onclose = () => {
159
+ ws.onclose = (ev) => {
139
160
  store.getState().setConnected(false);
140
161
  store.getState().setStatus('disconnected');
141
162
  this.ws = null;
142
163
  };
143
164
  });
144
165
  }
166
+ /**
167
+ * ws.onopen 必须用这个去获取,否者会丢失链接信息
168
+ * @param callback
169
+ * @returns
170
+ */
145
171
  listenConnect(callback) {
146
172
  const store = this.store;
147
173
  const { connected } = store.getState();
@@ -163,6 +189,28 @@ class QueryWs {
163
189
  });
164
190
  return cancel;
165
191
  }
192
+ listenClose(callback) {
193
+ const store = this.store;
194
+ const { status } = store.getState();
195
+ if (status === 'disconnected') {
196
+ callback();
197
+ }
198
+ const subscriptionOne = (selector, listener) => {
199
+ const unsubscribe = store.subscribe((newState, oldState) => {
200
+ if (selector(newState) !== selector(oldState)) {
201
+ listener(newState, oldState);
202
+ unsubscribe();
203
+ }
204
+ });
205
+ return unsubscribe;
206
+ };
207
+ const cancel = subscriptionOne((state) => state.status, (newState, oldState) => {
208
+ if (newState.status === 'disconnected') {
209
+ callback();
210
+ }
211
+ });
212
+ return cancel;
213
+ }
166
214
  onMessage(fn, opts) {
167
215
  const ws = this.ws;
168
216
  const isJson = opts?.isJson ?? true;
@@ -198,6 +246,13 @@ class QueryWs {
198
246
  store.getState().setConnected(false);
199
247
  store.getState().setStatus('disconnected');
200
248
  }
249
+ /**
250
+ * 发送消息
251
+ *
252
+ * @param data
253
+ * @param opts
254
+ * @returns
255
+ */
201
256
  send(data, opts) {
202
257
  const ws = this.ws;
203
258
  const isJson = opts?.isJson ?? true;
@@ -294,20 +349,22 @@ class Query {
294
349
  */
295
350
  async post(body, options) {
296
351
  const url = options?.url || this.url;
297
- const headers = { ...this.headers, ...options?.headers };
298
- const adapter = options?.adapter || this.adapter;
299
- const beforeRequest = options?.beforeRequest || this.beforeRequest;
300
- const afterResponse = options?.afterResponse || this.afterResponse;
301
- const timeout = options?.timeout || this.timeout;
352
+ const { headers, adapter, beforeRequest, afterResponse, timeout, ...rest } = options || {};
353
+ const _headers = { ...this.headers, ...headers };
354
+ const _adapter = adapter || this.adapter;
355
+ const _beforeRequest = beforeRequest || this.beforeRequest;
356
+ const _afterResponse = afterResponse || this.afterResponse;
357
+ const _timeout = timeout || this.timeout;
302
358
  const req = {
303
359
  url: url,
304
- headers: headers,
360
+ headers: _headers,
305
361
  body,
306
- timeout,
362
+ timeout: _timeout,
363
+ ...rest,
307
364
  };
308
365
  try {
309
- if (beforeRequest) {
310
- await beforeRequest(req);
366
+ if (_beforeRequest) {
367
+ await _beforeRequest(req);
311
368
  }
312
369
  }
313
370
  catch (e) {
@@ -335,11 +392,11 @@ class Query {
335
392
  }, 1000);
336
393
  });
337
394
  }
338
- return adapter(req).then(async (res) => {
395
+ return _adapter(req).then(async (res) => {
339
396
  try {
340
397
  setBaseResponse(res);
341
- if (afterResponse) {
342
- return await afterResponse(res, {
398
+ if (_afterResponse) {
399
+ return await _afterResponse(res, {
343
400
  req,
344
401
  res,
345
402
  fetch: adapter,
@@ -32,14 +32,39 @@ declare class QueryWs {
32
32
  connect(opts?: {
33
33
  timeout?: number;
34
34
  }): Promise<unknown>;
35
+ /**
36
+ * ws.onopen 必须用这个去获取,否者会丢失链接信息
37
+ * @param callback
38
+ * @returns
39
+ */
35
40
  listenConnect(callback: () => void): () => void;
41
+ listenClose(callback: () => void): () => void;
36
42
  onMessage<T = any, U = any>(fn: (data: U, event: MessageEvent) => void, opts?: {
43
+ /**
44
+ * 是否将数据转换为 JSON
45
+ */
37
46
  isJson?: boolean;
47
+ /**
48
+ * 选择器
49
+ */
38
50
  selector?: (data: T) => U;
39
51
  }): () => void;
40
52
  close(): void;
53
+ /**
54
+ * 发送消息
55
+ *
56
+ * @param data
57
+ * @param opts
58
+ * @returns
59
+ */
41
60
  send<T = any, U = any>(data: T, opts?: {
61
+ /**
62
+ * 是否将数据转换为 JSON
63
+ */
42
64
  isJson?: boolean;
65
+ /**
66
+ * 包装数据
67
+ */
43
68
  wrapper?: (data: T) => U;
44
69
  }): void;
45
70
  getOpen(): boolean;
package/dist/query-ws.js CHANGED
@@ -70,30 +70,42 @@ class QueryWs {
70
70
  */
71
71
  async connect(opts) {
72
72
  const store = this.store;
73
+ const that = this;
73
74
  const connected = store.getState().connected;
74
75
  if (connected) {
75
76
  return Promise.resolve(true);
76
77
  }
77
78
  return new Promise((resolve, reject) => {
78
- const ws = this.ws || new WebSocket(this.url);
79
- const timeout = opts?.timeout || 5 * 60 * 1000; // 默认 2 分钟
79
+ const ws = that.ws || new WebSocket(that.url);
80
+ const timeout = opts?.timeout || 5 * 60 * 1000; // 默认 5 分钟
80
81
  let timer = setTimeout(() => {
82
+ const isOpen = ws.readyState === WebSocket.OPEN;
83
+ if (isOpen) {
84
+ console.log('WebSocket 连接成功 in timer');
85
+ resolve(true);
86
+ return;
87
+ }
81
88
  console.error('WebSocket 连接超时');
82
89
  reject('timeout');
83
90
  }, timeout);
84
- ws.onopen = () => {
91
+ ws.onopen = (ev) => {
85
92
  store.getState().setConnected(true);
86
93
  store.getState().setStatus('connected');
87
94
  resolve(true);
88
95
  clearTimeout(timer);
89
96
  };
90
- ws.onclose = () => {
97
+ ws.onclose = (ev) => {
91
98
  store.getState().setConnected(false);
92
99
  store.getState().setStatus('disconnected');
93
100
  this.ws = null;
94
101
  };
95
102
  });
96
103
  }
104
+ /**
105
+ * ws.onopen 必须用这个去获取,否者会丢失链接信息
106
+ * @param callback
107
+ * @returns
108
+ */
97
109
  listenConnect(callback) {
98
110
  const store = this.store;
99
111
  const { connected } = store.getState();
@@ -115,6 +127,28 @@ class QueryWs {
115
127
  });
116
128
  return cancel;
117
129
  }
130
+ listenClose(callback) {
131
+ const store = this.store;
132
+ const { status } = store.getState();
133
+ if (status === 'disconnected') {
134
+ callback();
135
+ }
136
+ const subscriptionOne = (selector, listener) => {
137
+ const unsubscribe = store.subscribe((newState, oldState) => {
138
+ if (selector(newState) !== selector(oldState)) {
139
+ listener(newState, oldState);
140
+ unsubscribe();
141
+ }
142
+ });
143
+ return unsubscribe;
144
+ };
145
+ const cancel = subscriptionOne((state) => state.status, (newState, oldState) => {
146
+ if (newState.status === 'disconnected') {
147
+ callback();
148
+ }
149
+ });
150
+ return cancel;
151
+ }
118
152
  onMessage(fn, opts) {
119
153
  const ws = this.ws;
120
154
  const isJson = opts?.isJson ?? true;
@@ -150,6 +184,13 @@ class QueryWs {
150
184
  store.getState().setConnected(false);
151
185
  store.getState().setStatus('disconnected');
152
186
  }
187
+ /**
188
+ * 发送消息
189
+ *
190
+ * @param data
191
+ * @param opts
192
+ * @returns
193
+ */
153
194
  send(data, opts) {
154
195
  const ws = this.ws;
155
196
  const isJson = opts?.isJson ?? true;
package/dist/query.d.ts CHANGED
@@ -1,8 +1,11 @@
1
+ declare const methods: readonly ["GET", "POST"];
2
+ type Method = (typeof methods)[number];
1
3
  type AdapterOpts = {
2
4
  url: string;
3
5
  headers?: Record<string, string>;
4
6
  body?: Record<string, any>;
5
7
  timeout?: number;
8
+ method?: Method;
6
9
  };
7
10
  /**
8
11
  *
@@ -29,6 +32,8 @@ type QueryOpts = {
29
32
  adapter?: typeof adapter;
30
33
  headers?: Record<string, string>;
31
34
  timeout?: number;
35
+ method?: Method;
36
+ [key: string]: any;
32
37
  };
33
38
  type Data = {
34
39
  path?: string;
@@ -55,11 +60,11 @@ type Result<S = any> = {
55
60
  };
56
61
  type DataOpts = Partial<QueryOpts> & {
57
62
  beforeRequest?: Fn;
58
- afterResponse?: <S, U = S>(result: Result<S>, ctx?: {
63
+ afterResponse?: <S = any>(result: Result<S>, ctx?: {
59
64
  req?: any;
60
65
  res?: any;
61
66
  fetch?: any;
62
- }) => Promise<U>;
67
+ }) => Promise<Result<S>>;
63
68
  };
64
69
  /**
65
70
  * 设置基础响应, 设置 success 和 showError,
@@ -80,7 +85,7 @@ declare const setBaseResponse: (res: Result) => void;
80
85
  declare class Query {
81
86
  adapter: typeof adapter;
82
87
  url: string;
83
- beforeRequest?: Fn;
88
+ beforeRequest?: DataOpts['beforeRequest'];
84
89
  afterResponse?: DataOpts['afterResponse'];
85
90
  headers?: Record<string, string>;
86
91
  timeout?: number;
@@ -115,12 +120,12 @@ declare class Query {
115
120
  * 请求前处理,设置请求前处理函数
116
121
  * @param fn 处理函数
117
122
  */
118
- before(fn: Fn): void;
123
+ before(fn: DataOpts['beforeRequest']): void;
119
124
  /**
120
125
  * 请求后处理,设置请求后处理函数
121
126
  * @param fn 处理函数
122
127
  */
123
- after(fn: (result: Result, req?: any) => Promise<any>): void;
128
+ after(fn: DataOpts['afterResponse']): void;
124
129
  }
125
130
 
126
131
  export { Query, adapter, setBaseResponse };
package/dist/query.js CHANGED
@@ -11,15 +11,29 @@ const adapter = async (opts, overloadOpts) => {
11
11
  const timer = setTimeout(() => {
12
12
  controller.abort();
13
13
  }, timeout);
14
- return fetch(opts.url, {
15
- method: 'POST',
14
+ let method = overloadOpts?.method || opts.method || 'POST';
15
+ let origin = '';
16
+ let url;
17
+ if (opts?.url?.startsWith('http')) {
18
+ url = new URL(opts.url);
19
+ }
20
+ else {
21
+ origin = window?.location?.origin || 'http://localhost:11015';
22
+ url = new URL(opts.url, origin);
23
+ }
24
+ const isGet = method === 'GET';
25
+ if (isGet) {
26
+ url.search = new URLSearchParams(opts.body).toString();
27
+ }
28
+ return fetch(url, {
29
+ method: method.toUpperCase(),
16
30
  headers: {
17
31
  'Content-Type': 'application/json',
18
32
  ...opts.headers,
19
33
  },
20
- body: JSON.stringify(opts.body),
21
34
  signal,
22
35
  ...overloadOpts,
36
+ body: isGet ? undefined : JSON.stringify(opts.body),
23
37
  })
24
38
  .then((response) => {
25
39
  // 获取 Content-Type 头部信息
@@ -119,20 +133,22 @@ class Query {
119
133
  */
120
134
  async post(body, options) {
121
135
  const url = options?.url || this.url;
122
- const headers = { ...this.headers, ...options?.headers };
123
- const adapter = options?.adapter || this.adapter;
124
- const beforeRequest = options?.beforeRequest || this.beforeRequest;
125
- const afterResponse = options?.afterResponse || this.afterResponse;
126
- const timeout = options?.timeout || this.timeout;
136
+ const { headers, adapter, beforeRequest, afterResponse, timeout, ...rest } = options || {};
137
+ const _headers = { ...this.headers, ...headers };
138
+ const _adapter = adapter || this.adapter;
139
+ const _beforeRequest = beforeRequest || this.beforeRequest;
140
+ const _afterResponse = afterResponse || this.afterResponse;
141
+ const _timeout = timeout || this.timeout;
127
142
  const req = {
128
143
  url: url,
129
- headers: headers,
144
+ headers: _headers,
130
145
  body,
131
- timeout,
146
+ timeout: _timeout,
147
+ ...rest,
132
148
  };
133
149
  try {
134
- if (beforeRequest) {
135
- await beforeRequest(req);
150
+ if (_beforeRequest) {
151
+ await _beforeRequest(req);
136
152
  }
137
153
  }
138
154
  catch (e) {
@@ -160,11 +176,11 @@ class Query {
160
176
  }, 1000);
161
177
  });
162
178
  }
163
- return adapter(req).then(async (res) => {
179
+ return _adapter(req).then(async (res) => {
164
180
  try {
165
181
  setBaseResponse(res);
166
- if (afterResponse) {
167
- return await afterResponse(res, {
182
+ if (_afterResponse) {
183
+ return await _afterResponse(res, {
168
184
  req,
169
185
  res,
170
186
  fetch: adapter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevisual/query",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,6 +9,7 @@
9
9
  "scripts": {
10
10
  "build": "npm run clean && rollup -c",
11
11
  "build:app": "npm run build && rsync dist/* ../deploy/dist",
12
+ "dev:lib": "rollup -c -w",
12
13
  "clean": "rm -rf dist"
13
14
  },
14
15
  "files": [