@kevisual/query 0.0.14 → 0.0.16

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.
@@ -13,13 +13,21 @@ const adapter = async (opts, overloadOpts) => {
13
13
  controller.abort();
14
14
  }, timeout);
15
15
  let method = overloadOpts?.method || opts.method || 'POST';
16
- let url = new URL(opts.url, window.location.origin);
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
+ }
17
25
  const isGet = method === 'GET';
18
26
  if (isGet) {
19
27
  url.search = new URLSearchParams(opts.body).toString();
20
28
  }
21
29
  return fetch(url, {
22
- method: method,
30
+ method: method.toUpperCase(),
23
31
  headers: {
24
32
  'Content-Type': 'application/json',
25
33
  ...opts.headers,
@@ -40,14 +40,39 @@ declare class QueryWs {
40
40
  connect(opts?: {
41
41
  timeout?: number;
42
42
  }): Promise<unknown>;
43
+ /**
44
+ * ws.onopen 必须用这个去获取,否者会丢失链接信息
45
+ * @param callback
46
+ * @returns
47
+ */
43
48
  listenConnect(callback: () => void): () => void;
49
+ listenClose(callback: () => void): () => void;
44
50
  onMessage<T = any, U = any>(fn: (data: U, event: MessageEvent) => void, opts?: {
51
+ /**
52
+ * 是否将数据转换为 JSON
53
+ */
45
54
  isJson?: boolean;
55
+ /**
56
+ * 选择器
57
+ */
46
58
  selector?: (data: T) => U;
47
59
  }): () => void;
48
60
  close(): void;
61
+ /**
62
+ * 发送消息
63
+ *
64
+ * @param data
65
+ * @param opts
66
+ * @returns
67
+ */
49
68
  send<T = any, U = any>(data: T, opts?: {
69
+ /**
70
+ * 是否将数据转换为 JSON
71
+ */
50
72
  isJson?: boolean;
73
+ /**
74
+ * 包装数据
75
+ */
51
76
  wrapper?: (data: T) => U;
52
77
  }): void;
53
78
  getOpen(): boolean;
@@ -102,7 +127,7 @@ type DataOpts = Partial<QueryOpts$1> & {
102
127
  req?: any;
103
128
  res?: any;
104
129
  fetch?: any;
105
- }) => Promise<S>;
130
+ }) => Promise<Result<S>>;
106
131
  };
107
132
  /**
108
133
  * const query = new Query();
@@ -159,6 +184,19 @@ declare class Query {
159
184
  after(fn: DataOpts['afterResponse']): void;
160
185
  }
161
186
 
187
+ declare class BaseQuery<T extends Query> {
188
+ query: T;
189
+ constructor({ query }: {
190
+ query: T;
191
+ });
192
+ post<R = any, P = any>(data: P, options?: DataOpts): Promise<Result<R>>;
193
+ get<R = any, P = any>(data: P, options?: DataOpts): Promise<Result<R>>;
194
+ }
195
+
196
+
197
+
198
+
199
+
162
200
  type QueryOpts = {
163
201
  url?: string;
164
202
  adapter?: typeof adapter;
@@ -184,5 +222,5 @@ declare class QueryClient extends Query {
184
222
  removeToken(): void;
185
223
  }
186
224
 
187
- export { Query, QueryClient, QueryWs, adapter };
188
- export type { QueryOpts, QueryWsOpts };
225
+ export { BaseQuery, Query, QueryClient, QueryWs, adapter };
226
+ export type { Data, DataOpts, QueryOpts, QueryWsOpts, Result };
@@ -12,13 +12,21 @@ const adapter = async (opts, overloadOpts) => {
12
12
  controller.abort();
13
13
  }, timeout);
14
14
  let method = overloadOpts?.method || opts.method || 'POST';
15
- let url = new URL(opts.url, window.location.origin);
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
+ }
16
24
  const isGet = method === 'GET';
17
25
  if (isGet) {
18
26
  url.search = new URLSearchParams(opts.body).toString();
19
27
  }
20
28
  return fetch(url, {
21
- method: method,
29
+ method: method.toUpperCase(),
22
30
  headers: {
23
31
  'Content-Type': 'application/json',
24
32
  ...opts.headers,
@@ -124,30 +132,42 @@ class QueryWs {
124
132
  */
125
133
  async connect(opts) {
126
134
  const store = this.store;
135
+ const that = this;
127
136
  const connected = store.getState().connected;
128
137
  if (connected) {
129
138
  return Promise.resolve(true);
130
139
  }
131
140
  return new Promise((resolve, reject) => {
132
- const ws = this.ws || new WebSocket(this.url);
133
- 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 分钟
134
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
+ }
135
150
  console.error('WebSocket 连接超时');
136
151
  reject('timeout');
137
152
  }, timeout);
138
- ws.onopen = () => {
153
+ ws.onopen = (ev) => {
139
154
  store.getState().setConnected(true);
140
155
  store.getState().setStatus('connected');
141
156
  resolve(true);
142
157
  clearTimeout(timer);
143
158
  };
144
- ws.onclose = () => {
159
+ ws.onclose = (ev) => {
145
160
  store.getState().setConnected(false);
146
161
  store.getState().setStatus('disconnected');
147
162
  this.ws = null;
148
163
  };
149
164
  });
150
165
  }
166
+ /**
167
+ * ws.onopen 必须用这个去获取,否者会丢失链接信息
168
+ * @param callback
169
+ * @returns
170
+ */
151
171
  listenConnect(callback) {
152
172
  const store = this.store;
153
173
  const { connected } = store.getState();
@@ -169,6 +189,28 @@ class QueryWs {
169
189
  });
170
190
  return cancel;
171
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
+ }
172
214
  onMessage(fn, opts) {
173
215
  const ws = this.ws;
174
216
  const isJson = opts?.isJson ?? true;
@@ -204,6 +246,13 @@ class QueryWs {
204
246
  store.getState().setConnected(false);
205
247
  store.getState().setStatus('disconnected');
206
248
  }
249
+ /**
250
+ * 发送消息
251
+ *
252
+ * @param data
253
+ * @param opts
254
+ * @returns
255
+ */
207
256
  send(data, opts) {
208
257
  const ws = this.ws;
209
258
  const isJson = opts?.isJson ?? true;
@@ -381,6 +430,18 @@ class Query {
381
430
  this.afterResponse = fn;
382
431
  }
383
432
  }
433
+ class BaseQuery {
434
+ query;
435
+ constructor({ query }) {
436
+ this.query = query;
437
+ }
438
+ post(data, options) {
439
+ return this.query.post(data, options);
440
+ }
441
+ get(data, options) {
442
+ return this.query.get(data, options);
443
+ }
444
+ }
384
445
 
385
446
  /**
386
447
  * 前端调用后端QueryRouter
@@ -425,4 +486,4 @@ class QueryClient extends Query {
425
486
  // 移除默认生成的实例
426
487
  // export const client = new QueryClient();
427
488
 
428
- export { Query, QueryClient, QueryWs, adapter };
489
+ export { BaseQuery, Query, QueryClient, QueryWs, 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
@@ -64,7 +64,7 @@ type DataOpts = Partial<QueryOpts> & {
64
64
  req?: any;
65
65
  res?: any;
66
66
  fetch?: any;
67
- }) => Promise<S>;
67
+ }) => Promise<Result<S>>;
68
68
  };
69
69
  /**
70
70
  * 设置基础响应, 设置 success 和 showError,
@@ -128,5 +128,14 @@ declare class Query {
128
128
  after(fn: DataOpts['afterResponse']): void;
129
129
  }
130
130
 
131
- export { Query, adapter, setBaseResponse };
131
+ declare class BaseQuery<T extends Query> {
132
+ query: T;
133
+ constructor({ query }: {
134
+ query: T;
135
+ });
136
+ post<R = any, P = any>(data: P, options?: DataOpts): Promise<Result<R>>;
137
+ get<R = any, P = any>(data: P, options?: DataOpts): Promise<Result<R>>;
138
+ }
139
+
140
+ export { BaseQuery, Query, adapter, setBaseResponse };
132
141
  export type { Data, DataOpts, Fn, QueryOpts, Result };
package/dist/query.js CHANGED
@@ -12,13 +12,21 @@ const adapter = async (opts, overloadOpts) => {
12
12
  controller.abort();
13
13
  }, timeout);
14
14
  let method = overloadOpts?.method || opts.method || 'POST';
15
- let url = new URL(opts.url, window.location.origin);
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
+ }
16
24
  const isGet = method === 'GET';
17
25
  if (isGet) {
18
26
  url.search = new URLSearchParams(opts.body).toString();
19
27
  }
20
28
  return fetch(url, {
21
- method: method,
29
+ method: method.toUpperCase(),
22
30
  headers: {
23
31
  'Content-Type': 'application/json',
24
32
  ...opts.headers,
@@ -206,5 +214,17 @@ class Query {
206
214
  this.afterResponse = fn;
207
215
  }
208
216
  }
217
+ class BaseQuery {
218
+ query;
219
+ constructor({ query }) {
220
+ this.query = query;
221
+ }
222
+ post(data, options) {
223
+ return this.query.post(data, options);
224
+ }
225
+ get(data, options) {
226
+ return this.query.get(data, options);
227
+ }
228
+ }
209
229
 
210
- export { Query, adapter, setBaseResponse };
230
+ export { BaseQuery, Query, adapter, setBaseResponse };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevisual/query",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
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": [