@kevisual/api 0.0.15 → 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.
- package/package.json +1 -1
- package/query/query-proxy/index.ts +156 -72
package/package.json
CHANGED
|
@@ -4,13 +4,26 @@ import { filter } from '@kevisual/js-filter'
|
|
|
4
4
|
import { EventEmitter } from 'eventemitter3';
|
|
5
5
|
|
|
6
6
|
export const RouteTypeList = ['api', 'context', 'worker', 'page'] as const;
|
|
7
|
-
export type
|
|
7
|
+
export type RouterViewItemInfo = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage;
|
|
8
|
+
export type RouterViewItem<T = {}> = RouterViewItemInfo & T;
|
|
8
9
|
|
|
9
10
|
type RouteViewBase = {
|
|
10
11
|
id: string;
|
|
11
12
|
title: string;
|
|
12
13
|
description: string;
|
|
13
14
|
enabled?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* 提示问题
|
|
17
|
+
*/
|
|
18
|
+
question?: string;
|
|
19
|
+
/**
|
|
20
|
+
* 响应数据
|
|
21
|
+
*/
|
|
22
|
+
response?: any;
|
|
23
|
+
/**
|
|
24
|
+
* 默认动作配置
|
|
25
|
+
*/
|
|
26
|
+
action?: { path?: string; key?: string; id?: string; payload?: any;[key: string]: any };
|
|
14
27
|
}
|
|
15
28
|
export type RouterViewApi = {
|
|
16
29
|
type: 'api',
|
|
@@ -46,6 +59,30 @@ export type RouterViewWorker = {
|
|
|
46
59
|
}
|
|
47
60
|
} & RouteViewBase;
|
|
48
61
|
|
|
62
|
+
/**
|
|
63
|
+
* 去掉不需要保存都服务器的数据
|
|
64
|
+
* @param item
|
|
65
|
+
* @returns
|
|
66
|
+
*/
|
|
67
|
+
export const pickRouterViewData = (item: RouterViewItem) => {
|
|
68
|
+
const { question, action, response, ...rest } = item;
|
|
69
|
+
if (rest.type === 'api') {
|
|
70
|
+
if (rest.api) {
|
|
71
|
+
delete rest.api.query;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (rest.type === 'worker') {
|
|
75
|
+
if (rest.worker) {
|
|
76
|
+
delete rest.worker.worker;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (rest.type === 'context') {
|
|
80
|
+
if (rest.context) {
|
|
81
|
+
delete rest.context.router;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return rest
|
|
85
|
+
}
|
|
49
86
|
/**
|
|
50
87
|
* 注入 js 的url地址,使用importScripts加载
|
|
51
88
|
*/
|
|
@@ -91,56 +128,61 @@ export class QueryProxy {
|
|
|
91
128
|
return undefined;
|
|
92
129
|
}
|
|
93
130
|
}
|
|
94
|
-
|
|
131
|
+
initRouterViewQuery() {
|
|
95
132
|
this.routerViewItems = this.routerViewItems.map(item => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
133
|
+
return this.initRouterView(item);
|
|
134
|
+
}).filter(item => {
|
|
135
|
+
const enabled = item.enabled ?? true;
|
|
136
|
+
return enabled;
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
initRouterView(item: RouterViewItem) {
|
|
141
|
+
if (item.type === 'api' && item.api?.url) {
|
|
142
|
+
const url = item.api.url;
|
|
143
|
+
if (item?.api?.query) return item;
|
|
144
|
+
item['api'] = { url: url, query: new Query({ url: url }) };
|
|
145
|
+
}
|
|
146
|
+
if (item.type === 'worker' && item.worker?.url) {
|
|
147
|
+
let viewItem = item as RouterViewWorker;
|
|
148
|
+
if (!item.worker?.workerOptions?.type) {
|
|
149
|
+
item.worker.workerOptions = { ...item.worker.workerOptions, type: 'module' };
|
|
100
150
|
}
|
|
101
|
-
if (item.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) {
|
|
116
|
-
console.debug('注册serviceWorker成功 ', registration.scope);
|
|
117
|
-
}, function (err) {
|
|
118
|
-
console.debug('注册 serviceWorker 失败: ', err);
|
|
119
|
-
});
|
|
120
|
-
} else {
|
|
121
|
-
console.warn('当前浏览器不支持serviceWorker');
|
|
122
|
-
}
|
|
151
|
+
if (item.worker.worker) {
|
|
152
|
+
return item;
|
|
153
|
+
}
|
|
154
|
+
let worker: Worker | SharedWorker | ServiceWorker | undefined = undefined;
|
|
155
|
+
if (item.worker.type === 'SharedWorker') {
|
|
156
|
+
worker = new SharedWorker(item.worker.url, item.worker.workerOptions);
|
|
157
|
+
worker.port.start();
|
|
158
|
+
} else if (viewItem.worker.type === 'serviceWorker') {
|
|
159
|
+
if ('serviceWorker' in navigator) {
|
|
160
|
+
navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) {
|
|
161
|
+
console.debug('注册serviceWorker成功 ', registration.scope);
|
|
162
|
+
}, function (err) {
|
|
163
|
+
console.debug('注册 serviceWorker 失败: ', err);
|
|
164
|
+
});
|
|
123
165
|
} else {
|
|
124
|
-
|
|
166
|
+
console.warn('当前浏览器不支持serviceWorker');
|
|
125
167
|
}
|
|
126
|
-
|
|
168
|
+
} else {
|
|
169
|
+
worker = new Worker(viewItem.worker.url, item.worker.workerOptions);
|
|
127
170
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const context = globalThis['context'] || {}
|
|
134
|
-
const router = context[item.context.key] as QueryRouterServer;
|
|
135
|
-
if (router) {
|
|
136
|
-
item['context']['router'] = router;
|
|
137
|
-
}
|
|
171
|
+
viewItem['worker']['worker'] = worker;
|
|
172
|
+
}
|
|
173
|
+
if (item.type === 'context' && item.context?.key) {
|
|
174
|
+
if (item.context?.router) {
|
|
175
|
+
return item;
|
|
138
176
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
177
|
+
// @ts-ignore
|
|
178
|
+
const context = globalThis['context'] || {}
|
|
179
|
+
const router = context[item.context.key] as QueryRouterServer;
|
|
180
|
+
if (router) {
|
|
181
|
+
item['context']['router'] = router;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return item;
|
|
185
|
+
|
|
144
186
|
}
|
|
145
187
|
|
|
146
188
|
/**
|
|
@@ -248,7 +290,35 @@ export class QueryProxy {
|
|
|
248
290
|
generateId() {
|
|
249
291
|
return 'route_' + Math.random().toString(36).substring(2, 9);
|
|
250
292
|
}
|
|
251
|
-
async
|
|
293
|
+
async callWorker(msg: any, viewItem: RouterViewWorker['worker']): Promise<Result> {
|
|
294
|
+
const that = this;
|
|
295
|
+
const requestId = this.generateId();
|
|
296
|
+
const worker = viewItem?.worker;
|
|
297
|
+
if (!worker) {
|
|
298
|
+
return { code: 500, message: 'Worker未初始化' };
|
|
299
|
+
}
|
|
300
|
+
let port: MessagePort | Worker | ServiceWorker;
|
|
301
|
+
if (viewItem.type === 'SharedWorker') {
|
|
302
|
+
port = (worker as SharedWorker).port;
|
|
303
|
+
} else {
|
|
304
|
+
port = worker as Worker | ServiceWorker;
|
|
305
|
+
}
|
|
306
|
+
port.postMessage({
|
|
307
|
+
...msg,
|
|
308
|
+
requestId: requestId,
|
|
309
|
+
})
|
|
310
|
+
return new Promise((resolve) => {
|
|
311
|
+
const timer = setTimeout(() => {
|
|
312
|
+
that.emitter.removeAllListeners(requestId);
|
|
313
|
+
resolve({ code: 500, message: '请求超时' });
|
|
314
|
+
}, 3 * 60 * 1000); // 3分钟超时
|
|
315
|
+
that.emitter.once(requestId, (res: any) => {
|
|
316
|
+
clearTimeout(timer);
|
|
317
|
+
resolve(res);
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
async initWorker(item?: RouterViewWorker, initRoutes: boolean = true) {
|
|
252
322
|
const that = this;
|
|
253
323
|
if (!item?.worker?.url) {
|
|
254
324
|
console.warn('Worker URL not provided');
|
|
@@ -278,33 +348,10 @@ export class QueryProxy {
|
|
|
278
348
|
} else {
|
|
279
349
|
(worker as Worker).onmessage = callResponse;
|
|
280
350
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const worker = viewItem?.worker;
|
|
284
|
-
if (!worker) {
|
|
285
|
-
return { code: 500, message: 'Worker未初始化' };
|
|
286
|
-
}
|
|
287
|
-
let port: MessagePort | Worker | ServiceWorker;
|
|
288
|
-
if (viewItem.type === 'SharedWorker') {
|
|
289
|
-
port = (worker as SharedWorker).port;
|
|
290
|
-
} else {
|
|
291
|
-
port = worker as Worker | ServiceWorker;
|
|
292
|
-
}
|
|
293
|
-
port.postMessage({
|
|
294
|
-
...msg,
|
|
295
|
-
requestId: requestId,
|
|
296
|
-
})
|
|
297
|
-
return new Promise((resolve) => {
|
|
298
|
-
const timer = setTimeout(() => {
|
|
299
|
-
that.emitter.removeAllListeners(requestId);
|
|
300
|
-
resolve({ code: 500, message: '请求超时' });
|
|
301
|
-
}, 3 * 60 * 1000); // 3分钟超时
|
|
302
|
-
that.emitter.once(requestId, (res: any) => {
|
|
303
|
-
clearTimeout(timer);
|
|
304
|
-
resolve(res);
|
|
305
|
-
});
|
|
306
|
-
});
|
|
351
|
+
if (!initRoutes) {
|
|
352
|
+
return;
|
|
307
353
|
}
|
|
354
|
+
const callWorker = this.callWorker.bind(this);
|
|
308
355
|
|
|
309
356
|
const res = await callWorker({
|
|
310
357
|
path: "router",
|
|
@@ -393,6 +440,43 @@ export class QueryProxy {
|
|
|
393
440
|
async run(msg: { id?: string, path?: string, key?: string }) {
|
|
394
441
|
return await this.router.run(msg);
|
|
395
442
|
}
|
|
443
|
+
|
|
444
|
+
async runByRouteView(routeView: RouterViewItem) {
|
|
445
|
+
if (routeView.response) {
|
|
446
|
+
return routeView;
|
|
447
|
+
}
|
|
448
|
+
const item = this.initRouterView(routeView);
|
|
449
|
+
if (item.type === 'api' && item.api?.url) {
|
|
450
|
+
const query = item.api.query!;
|
|
451
|
+
const res = await query.post<any>(item.action || {});
|
|
452
|
+
item.response = res;
|
|
453
|
+
return item;
|
|
454
|
+
} else if (item.type === 'api') {
|
|
455
|
+
item.response = { code: 500, message: 'API URL未配置' };
|
|
456
|
+
return item;
|
|
457
|
+
}
|
|
458
|
+
if (item.type === 'context' && item.context?.router) {
|
|
459
|
+
const router = item.context.router;
|
|
460
|
+
const res = await router.run(item.action || {});
|
|
461
|
+
item.response = res;
|
|
462
|
+
return item;
|
|
463
|
+
}
|
|
464
|
+
if (item.type === 'page') {
|
|
465
|
+
await this.initPage(item);
|
|
466
|
+
const res = await this.router.run(item.action || {});
|
|
467
|
+
item.response = res;
|
|
468
|
+
return item;
|
|
469
|
+
}
|
|
470
|
+
if (item.type === 'worker' && item.worker?.worker) {
|
|
471
|
+
await this.initWorker(item, false);
|
|
472
|
+
const callWorker = this.callWorker.bind(this);
|
|
473
|
+
const res = await callWorker(item.action || {}, item.worker);
|
|
474
|
+
item.response = res;
|
|
475
|
+
return item;
|
|
476
|
+
}
|
|
477
|
+
item.response = { code: 500, message: '无法处理的路由类型' };
|
|
478
|
+
return item;
|
|
479
|
+
}
|
|
396
480
|
}
|
|
397
481
|
|
|
398
482
|
type RouterItem = {
|