@kevisual/api 0.0.12 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kevisual/api",
3
- "version": "0.0.12",
3
+ "version": "0.0.15",
4
4
  "description": "",
5
5
  "main": "mod.ts",
6
6
  "scripts": {
@@ -18,12 +18,12 @@
18
18
  "keywords": [],
19
19
  "author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
20
20
  "license": "MIT",
21
- "packageManager": "pnpm@10.26.2",
21
+ "packageManager": "pnpm@10.27.0",
22
22
  "type": "module",
23
23
  "devDependencies": {
24
24
  "@kevisual/cache": "^0.0.4",
25
25
  "@kevisual/query": "^0.0.33",
26
- "@kevisual/router": "^0.0.51",
26
+ "@kevisual/router": "^0.0.52",
27
27
  "@kevisual/types": "^0.0.10",
28
28
  "@kevisual/use-config": "^1.0.21",
29
29
  "@types/bun": "^1.3.5",
@@ -32,7 +32,7 @@
32
32
  "fast-glob": "^3.3.3"
33
33
  },
34
34
  "dependencies": {
35
- "@kevisual/js-filter": "^0.0.2",
35
+ "@kevisual/js-filter": "^0.0.3",
36
36
  "@kevisual/load": "^0.0.6",
37
37
  "es-toolkit": "^1.43.0",
38
38
  "eventemitter3": "^5.0.1",
@@ -3,39 +3,59 @@ import { QueryRouterServer, Route } from '@kevisual/router/src/route.ts';
3
3
  import { filter } from '@kevisual/js-filter'
4
4
  import { EventEmitter } from 'eventemitter3';
5
5
 
6
- export type RouterViewItem = RouterViewApi | RouterViewContext | RouterViewWorker;
7
- export type RouterViewApi = {
6
+ export const RouteTypeList = ['api', 'context', 'worker', 'page'] as const;
7
+ export type RouterViewItem = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage;
8
+
9
+ type RouteViewBase = {
10
+ id: string;
8
11
  title: string;
9
12
  description: string;
13
+ enabled?: boolean;
14
+ }
15
+ export type RouterViewApi = {
10
16
  type: 'api',
11
17
  api: {
12
18
  url: string,
13
- // 已初始化的query实例
19
+ // 已初始化的query实例,不需要编辑配置
14
20
  query?: Query
15
21
  }
16
- }
22
+ } & RouteViewBase;
17
23
 
18
24
  export type RouterViewContext = {
19
- title: string;
20
- description: string;
21
25
  type: 'context',
22
26
  context: {
23
27
  key: string,
24
- // 从context中获取router
28
+ // 从context中获取router,不需要编辑配置
25
29
  router?: QueryRouterServer
26
30
  }
27
- }
31
+ } & RouteViewBase;
28
32
  export type RouterViewWorker = {
29
- title: string;
30
- description: string;
31
33
  type: 'worker',
32
34
  worker: {
33
35
  type: 'Worker' | 'SharedWorker' | 'serviceWorker',
34
36
  url: string,
35
- // 已初始化的worker实例
36
- worker?: Worker | SharedWorker | ServiceWorker
37
+ // 已初始化的worker实例,不需要编辑配置
38
+ worker?: Worker | SharedWorker | ServiceWorker,
39
+ /**
40
+ * worker选项
41
+ * default: { type: 'module' }
42
+ */
43
+ workerOptions?: {
44
+ type: 'module' | 'classic'
45
+ }
46
+ }
47
+ } & RouteViewBase;
48
+
49
+ /**
50
+ * 注入 js 的url地址,使用importScripts加载
51
+ */
52
+ export type RouteViewPage = {
53
+ type: 'page',
54
+ page: {
55
+ url: string,
37
56
  }
38
- }
57
+ } & RouteViewBase;
58
+
39
59
  export type RouterViewQuery = {
40
60
  id: string,
41
61
  query: string,
@@ -72,7 +92,7 @@ export class QueryProxy {
72
92
  }
73
93
  }
74
94
  async initRouterViewQuery() {
75
- this.routerViewItems = this.routerViewItems?.map(item => {
95
+ this.routerViewItems = this.routerViewItems.map(item => {
76
96
  if (item.type === 'api' && item.api?.url) {
77
97
  const url = item.api.url;
78
98
  if (item?.api?.query) return item;
@@ -80,16 +100,19 @@ export class QueryProxy {
80
100
  }
81
101
  if (item.type === 'worker' && item.worker?.url) {
82
102
  let viewItem = item as RouterViewWorker;
103
+ if (!item.worker?.workerOptions?.type) {
104
+ item.worker.workerOptions = { ...item.worker.workerOptions, type: 'module' };
105
+ }
83
106
  if (item.worker.worker) {
84
107
  return item;
85
108
  }
86
109
  let worker: Worker | SharedWorker | ServiceWorker | undefined = undefined;
87
110
  if (item.worker.type === 'SharedWorker') {
88
- worker = new SharedWorker(item.worker.url);
111
+ worker = new SharedWorker(item.worker.url, item.worker.workerOptions);
89
112
  worker.port.start();
90
113
  } else if (viewItem.worker.type === 'serviceWorker') {
91
114
  if ('serviceWorker' in navigator) {
92
- navigator.serviceWorker.register(viewItem.worker.url).then(function (registration) {
115
+ navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) {
93
116
  console.debug('注册serviceWorker成功 ', registration.scope);
94
117
  }, function (err) {
95
118
  console.debug('注册 serviceWorker 失败: ', err);
@@ -98,7 +121,7 @@ export class QueryProxy {
98
121
  console.warn('当前浏览器不支持serviceWorker');
99
122
  }
100
123
  } else {
101
- worker = new Worker(viewItem.worker.url);
124
+ worker = new Worker(viewItem.worker.url, item.worker.workerOptions);
102
125
  }
103
126
  viewItem['worker']['worker'] = worker;
104
127
  }
@@ -114,6 +137,9 @@ export class QueryProxy {
114
137
  }
115
138
  }
116
139
  return item;
140
+ }).filter(item => {
141
+ const enabled = item.enabled ?? true;
142
+ return enabled;
117
143
  });
118
144
  }
119
145
 
@@ -124,21 +150,44 @@ export class QueryProxy {
124
150
  async init() {
125
151
  const routerViewItems = this.routerViewItems || [];
126
152
  if (routerViewItems.length === 0) {
153
+ // 默认初始化api类型路由
127
154
  await this.initApi();
128
155
  return;
129
156
  }
130
157
  for (const item of routerViewItems) {
131
158
  switch (item.type) {
132
159
  case 'api':
133
- this.initApi(item);
160
+ await this.initApi(item);
134
161
  break;
135
162
  case 'context':
163
+ await this.initContext(item);
136
164
  break;
137
165
  case 'worker':
138
- this.initWorker(item);
166
+ await this.initWorker(item);
167
+ break;
168
+ case 'page':
169
+ await this.initPage(item);
139
170
  break;
140
171
  }
141
172
  }
173
+ this.emitter.emit('initComplete');
174
+ }
175
+ /**
176
+ * 监听初始化完成
177
+ * @returns
178
+ */
179
+ async listenInitComplete(): Promise<boolean> {
180
+ return new Promise((resolve) => {
181
+ const timer = setTimeout(() => {
182
+ this.emitter.removeAllListeners('initComplete');
183
+ resolve(false);
184
+ }, 3 * 60000); // 3分钟超时
185
+ const func = () => {
186
+ clearTimeout(timer);
187
+ resolve(true);
188
+ }
189
+ this.emitter.once('initComplete', func);
190
+ });
142
191
  }
143
192
  async initApi(item?: RouterViewApi) {
144
193
  const that = this;
@@ -152,12 +201,14 @@ export class QueryProxy {
152
201
  for (const r of _list) {
153
202
  if (r.path || r.id) {
154
203
  console.debug(`注册路由: [${r.path}] ${r?.key}`, 'API');
204
+ let metadata = r.metadata || {};
205
+ metadata.viewItem = item;
155
206
  this.router.route({
156
207
  path: r.path,
157
208
  key: r.key || '',
158
209
  id: r.id,
159
210
  description: r.description,
160
- metadata: r.metadata,
211
+ metadata: metadata,
161
212
  }).define(async (ctx) => {
162
213
  const msg = { ...ctx.query };
163
214
  if (msg.token === undefined && that.token !== undefined) {
@@ -180,12 +231,14 @@ export class QueryProxy {
180
231
  const routes = router.getList();
181
232
  for (const r of routes) {
182
233
  console.debug(`注册路由: [${r.path}] ${r?.key}`, 'Context');
234
+ let metadata = r.metadata || {};
235
+ metadata.viewItem = item;
183
236
  this.router.route({
184
237
  path: r.path,
185
238
  key: r.key || '',
186
239
  id: r.id,
187
240
  description: r.description,
188
- metadata: r.metadata,
241
+ metadata: metadata,
189
242
  }).define(async (ctx) => {
190
243
  const res = await router.run({ path: r.path, key: r.key, ...ctx.query });
191
244
  ctx.forward(res)
@@ -207,14 +260,23 @@ export class QueryProxy {
207
260
  console.warn('Worker not initialized');
208
261
  return;
209
262
  }
210
- if (item.worker.type === 'SharedWorker') {
211
- const port = (worker as SharedWorker).port;
212
- port.onmessage = function (e) {
213
- const msg = e.data;
263
+ const callResponse = (e: MessageEvent) => {
264
+ const msg = e.data;
265
+ if (msg.requestId) {
214
266
  const requestId = msg.requestId;
215
267
  that.emitter.emit(requestId, msg);
216
- };
268
+ } else {
269
+ that.router.run(msg);
270
+ }
271
+ }
272
+ if (item.worker.type === 'SharedWorker') {
273
+ const port = (worker as SharedWorker).port;
274
+ port.onmessage = callResponse;
217
275
  port.start();
276
+ } else if (item.worker.type === 'serviceWorker') {
277
+ navigator.serviceWorker.addEventListener('message', callResponse);
278
+ } else {
279
+ (worker as Worker).onmessage = callResponse;
218
280
  }
219
281
  const callWorker = async (msg: any, viewItem: RouterViewWorker['worker']): Promise<Result> => {
220
282
  const requestId = this.generateId();
@@ -243,6 +305,7 @@ export class QueryProxy {
243
305
  });
244
306
  });
245
307
  }
308
+
246
309
  const res = await callWorker({
247
310
  path: "router",
248
311
  key: 'list',
@@ -257,12 +320,14 @@ export class QueryProxy {
257
320
  for (const r of _list) {
258
321
  if (r.path || r.id) {
259
322
  console.debug(`注册路由: [${r.path}] ${r?.key}`, 'API');
323
+ let metadata = r.metadata || {};
324
+ metadata.viewItem = item;
260
325
  this.router.route({
261
326
  path: r.path,
262
327
  key: r.key || '',
263
328
  id: r.id,
264
329
  description: r.description,
265
- metadata: r.metadata,
330
+ metadata: metadata,
266
331
  }).define(async (ctx) => {
267
332
  const msg = { ...ctx.query };
268
333
  if (msg.token === undefined && that.token !== undefined) {
@@ -274,6 +339,23 @@ export class QueryProxy {
274
339
  }
275
340
  }
276
341
  }
342
+ async initPage(item?: RouteViewPage) {
343
+ if (!item?.page?.url) {
344
+ console.warn('Page地址未提供');
345
+ return;
346
+ }
347
+ const url = item.page.url;
348
+ try {
349
+ if (typeof window !== 'undefined') {
350
+ await import(url).then((module) => { }).catch((err) => {
351
+ console.error('引入Page脚本失败:', url, err);
352
+ });
353
+ }
354
+ } catch (e) {
355
+ console.warn('引入Page脚本失败:', url, e);
356
+ return;
357
+ }
358
+ }
277
359
  /**
278
360
  * 列出路由
279
361
  * @param filter
@@ -296,6 +378,13 @@ export class QueryProxy {
296
378
  }
297
379
  return routes;
298
380
  }
381
+ async getViewQuery(viewId: string) {
382
+ const view = this.views.find(v => v.id === viewId);
383
+ if (view) {
384
+ return view.query;
385
+ }
386
+ return undefined;
387
+ }
299
388
  /**
300
389
  * 运行路由
301
390
  * @param msg