@kevisual/api 0.0.1 → 0.0.6
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/mod.ts +1 -0
- package/package.json +24 -15
- package/query/kevisual.json +7 -11
- package/query/query-ai/defines/ai.ts +1 -1
- package/query/query-app/defines/user-app-list.ts +1 -1
- package/query/query-app/defines/user-app.ts +1 -1
- package/query/query-app/query-app.ts +14 -0
- package/query/query-config/query-config.ts +121 -0
- package/query/query-login/query-login.ts +49 -1
- package/query/query-proxy/index.ts +68 -0
- package/query/query-secret/query-secret.ts +64 -0
- package/query/query-shop/defines/query-shop-define.ts +1 -1
- package/query/query-shop/query-shop.ts +2 -3
- package/query/query-upload/query-upload.ts +2 -1
- package/readme.md +169 -0
- package/query/query-mark/query-mark.ts +0 -154
package/mod.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './query/query-proxy/index.ts';
|
package/package.json
CHANGED
|
@@ -1,30 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kevisual/api",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "mod.ts",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"build": "bun bun.config.
|
|
7
|
+
"build": "bun run bun.config.ts",
|
|
8
|
+
"postbuild": "bun bun.copy.config.mjs"
|
|
8
9
|
},
|
|
9
|
-
"keywords": [],
|
|
10
|
-
"files": [
|
|
11
|
-
"src",
|
|
12
|
-
"query",
|
|
13
|
-
"dist"
|
|
14
|
-
],
|
|
15
10
|
"publishConfig": {
|
|
16
11
|
"access": "public"
|
|
17
12
|
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"query",
|
|
16
|
+
"mod.ts"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [],
|
|
18
19
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
|
19
20
|
"license": "MIT",
|
|
20
|
-
"packageManager": "pnpm@10.
|
|
21
|
+
"packageManager": "pnpm@10.26.2",
|
|
21
22
|
"type": "module",
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"@kevisual/query": "^0.0.18",
|
|
24
|
-
"@kevisual/router": "^0.0.20"
|
|
25
|
-
},
|
|
26
23
|
"devDependencies": {
|
|
24
|
+
"@kevisual/cache": "^0.0.4",
|
|
25
|
+
"@kevisual/query": "^0.0.33",
|
|
26
|
+
"@kevisual/router": "^0.0.51",
|
|
27
27
|
"@kevisual/types": "^0.0.10",
|
|
28
|
-
"@
|
|
28
|
+
"@kevisual/use-config": "^1.0.21",
|
|
29
|
+
"@types/bun": "^1.3.5",
|
|
30
|
+
"@types/node": "^25.0.3",
|
|
31
|
+
"dotenv": "^17.2.3",
|
|
32
|
+
"fast-glob": "^3.3.3"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@kevisual/load": "^0.0.6",
|
|
36
|
+
"es-toolkit": "^1.43.0",
|
|
37
|
+
"nanoid": "^5.1.6"
|
|
29
38
|
}
|
|
30
39
|
}
|
package/query/kevisual.json
CHANGED
|
@@ -1,24 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
-
"$schema": "https://kevisual.xiongxiao.me/root/ai/kevisual/tools/kevisual-sync/schema.json?v=2",
|
|
3
2
|
"metadata": {
|
|
3
|
+
"name": "kevisual",
|
|
4
4
|
"share": "public"
|
|
5
5
|
},
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
"registry": "https://kevisual.cn/root/ai/kevisual/common/query/api",
|
|
7
|
+
"clone": {
|
|
8
|
+
".": {
|
|
9
9
|
"enabled": true
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
-
"
|
|
12
|
+
"syncd": [
|
|
13
13
|
{
|
|
14
14
|
"files": [
|
|
15
|
-
"
|
|
15
|
+
"**/*"
|
|
16
16
|
],
|
|
17
|
-
"
|
|
18
|
-
"registry": "https://kevisual.xiongxiao.me/root/ai/code/registry",
|
|
19
|
-
"replace": {
|
|
20
|
-
"src/": ""
|
|
21
|
-
}
|
|
17
|
+
"registry": ""
|
|
22
18
|
}
|
|
23
19
|
],
|
|
24
20
|
"sync": {}
|
|
@@ -15,4 +15,18 @@ export class QueryApp extends BaseQuery {
|
|
|
15
15
|
getList(data: any, opts?: DataOpts) {
|
|
16
16
|
return this.appDefine.queryChain('listApps').post(data, opts);
|
|
17
17
|
}
|
|
18
|
+
getPublicApp(data: any, opts?: DataOpts) {
|
|
19
|
+
return this.query.post({
|
|
20
|
+
path: 'app',
|
|
21
|
+
key: 'getApp',
|
|
22
|
+
data: data,
|
|
23
|
+
}, opts);
|
|
24
|
+
}
|
|
25
|
+
getApp(data: any, opts?: DataOpts) {
|
|
26
|
+
return this.query.post({
|
|
27
|
+
path: 'app',
|
|
28
|
+
key: 'get',
|
|
29
|
+
data: data,
|
|
30
|
+
}, opts);
|
|
31
|
+
}
|
|
18
32
|
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置查询
|
|
3
|
+
* @updatedAt 2025-12-03 10:33:00
|
|
4
|
+
*/
|
|
5
|
+
import { Query } from '@kevisual/query';
|
|
6
|
+
import type { Result } from '@kevisual/query/query';
|
|
7
|
+
type QueryConfigOpts = {
|
|
8
|
+
query?: Query;
|
|
9
|
+
};
|
|
10
|
+
export type Config<T = any> = {
|
|
11
|
+
id?: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
key?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
data?: T;
|
|
16
|
+
createdAt?: string;
|
|
17
|
+
updatedAt?: string;
|
|
18
|
+
};
|
|
19
|
+
export type UploadConfig = {
|
|
20
|
+
key?: string;
|
|
21
|
+
version?: string;
|
|
22
|
+
};
|
|
23
|
+
type PostOpts = {
|
|
24
|
+
token?: string;
|
|
25
|
+
payload?: Record<string, any>;
|
|
26
|
+
};
|
|
27
|
+
export const defaultConfigKeys = ['upload.json', 'workspace.json', 'ai.json', 'user.json', 'life.json'] as const;
|
|
28
|
+
type DefaultConfigKey = (typeof defaultConfigKeys)[number];
|
|
29
|
+
|
|
30
|
+
export class QueryConfig {
|
|
31
|
+
query: Query;
|
|
32
|
+
constructor(opts?: QueryConfigOpts) {
|
|
33
|
+
this.query = opts?.query || new Query();
|
|
34
|
+
}
|
|
35
|
+
async post<T = Config>(data: any) {
|
|
36
|
+
return this.query.post<T>({ path: 'config', ...data });
|
|
37
|
+
}
|
|
38
|
+
async getConfig({ id, key }: { id?: string; key?: string }, opts?: PostOpts) {
|
|
39
|
+
return this.post({
|
|
40
|
+
key: 'get',
|
|
41
|
+
data: {
|
|
42
|
+
id,
|
|
43
|
+
key,
|
|
44
|
+
},
|
|
45
|
+
...opts,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async updateConfig(data: Config, opts?: PostOpts) {
|
|
49
|
+
return this.post({
|
|
50
|
+
key: 'update',
|
|
51
|
+
data,
|
|
52
|
+
...opts,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async deleteConfig(data: { id?: string, key?: string }, opts?: PostOpts) {
|
|
56
|
+
console.log('Delete Config Params:', data);
|
|
57
|
+
return this.post({
|
|
58
|
+
key: 'delete',
|
|
59
|
+
data,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async listConfig(opts?: PostOpts) {
|
|
63
|
+
return this.post<{ list: Config[] }>({
|
|
64
|
+
key: 'list',
|
|
65
|
+
...opts,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 获取上传配置
|
|
70
|
+
* @returns
|
|
71
|
+
*/
|
|
72
|
+
async getUploadConfig(opts?: PostOpts) {
|
|
73
|
+
return this.post<Result<Config<UploadConfig>>>({
|
|
74
|
+
key: 'getUploadConfig',
|
|
75
|
+
...opts,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 更新上传配置
|
|
80
|
+
* @param data
|
|
81
|
+
* @returns
|
|
82
|
+
*/
|
|
83
|
+
async updateUploadConfig(data: Config, opts?: PostOpts) {
|
|
84
|
+
return this.post<Result<Config<UploadConfig>>>({
|
|
85
|
+
key: 'updateUploadConfig',
|
|
86
|
+
data,
|
|
87
|
+
...opts,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 检测配置是否存在
|
|
93
|
+
* @param id
|
|
94
|
+
* @returns
|
|
95
|
+
*/
|
|
96
|
+
async detectConfig(opts?: PostOpts) {
|
|
97
|
+
return this.post<{ updateList: Config[] }>({
|
|
98
|
+
key: 'detect',
|
|
99
|
+
...opts,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 获取配置, 获取默认的配置项
|
|
104
|
+
* @param key
|
|
105
|
+
* @returns
|
|
106
|
+
*/
|
|
107
|
+
async getConfigByKey(key: DefaultConfigKey, opts?: PostOpts) {
|
|
108
|
+
return this.post<Result<Config>>({
|
|
109
|
+
key: 'defaultConfig',
|
|
110
|
+
configKey: key,
|
|
111
|
+
...opts,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
async getByKey<T = any>(key: string, opts?: PostOpts) {
|
|
115
|
+
return this.post<Result<Config<T>>>({
|
|
116
|
+
key: 'get',
|
|
117
|
+
...opts,
|
|
118
|
+
data: { key },
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { Result, DataOpts } from '@kevisual/query/query';
|
|
|
3
3
|
import { setBaseResponse } from '@kevisual/query/query';
|
|
4
4
|
import { LoginCacheStore, CacheStore } from './login-cache.ts';
|
|
5
5
|
import { Cache } from './login-cache.ts';
|
|
6
|
-
|
|
6
|
+
import { BaseLoad } from '@kevisual/load';
|
|
7
7
|
export type QueryLoginOpts = {
|
|
8
8
|
query?: Query;
|
|
9
9
|
isBrowser?: boolean;
|
|
@@ -418,6 +418,12 @@ export class QueryLogin extends BaseQuery {
|
|
|
418
418
|
}
|
|
419
419
|
/**
|
|
420
420
|
* 使用web登录,创建url地址, 需要MD5和jsonwebtoken
|
|
421
|
+
*
|
|
422
|
+
*
|
|
423
|
+
|
|
424
|
+
import MD5 from 'crypto-js/md5.js';
|
|
425
|
+
import jsonwebtoken from 'jsonwebtoken';
|
|
426
|
+
|
|
421
427
|
*/
|
|
422
428
|
loginWithWeb(baseURL: string, { MD5, jsonwebtoken }: { MD5: any; jsonwebtoken: any }) {
|
|
423
429
|
const randomId = Math.random().toString(36).substring(2, 15);
|
|
@@ -431,4 +437,46 @@ export class QueryLogin extends BaseQuery {
|
|
|
431
437
|
const url = `${baseURL}/api/router?path=user&key=webLogin&p&loginToken=${token}&sign=${sign}&randomId=${randomId}`;
|
|
432
438
|
return { url, token, tokenSecret };
|
|
433
439
|
}
|
|
440
|
+
/**
|
|
441
|
+
*轮询登录状态
|
|
442
|
+
*
|
|
443
|
+
*
|
|
444
|
+
*
|
|
445
|
+
const res = queryLogin.loginWithWeb(baseURL, { MD5, jsonwebtoken });
|
|
446
|
+
await pollLoginStatus(res.token, { tokenSecret: res.tokenSecret });
|
|
447
|
+
* 轮询登录状态
|
|
448
|
+
*/
|
|
449
|
+
async pollLoginStatus(data: { token: string; tokenSecret: string }) {
|
|
450
|
+
const token = data.token;
|
|
451
|
+
const load = new BaseLoad();
|
|
452
|
+
load.load(
|
|
453
|
+
async () => {
|
|
454
|
+
const res = await this.checkLoginStatus(token);
|
|
455
|
+
if (res.code === 500) {
|
|
456
|
+
load.cancel('check-login-status');
|
|
457
|
+
}
|
|
458
|
+
return res;
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
key: 'check-login-status',
|
|
462
|
+
isReRun: true,
|
|
463
|
+
checkSuccess: (data) => {
|
|
464
|
+
return data?.code === 200;
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
);
|
|
468
|
+
const res = await load.hasLoaded('check-login-status', {
|
|
469
|
+
timeout: 60 * 3 * 1000, // 3分钟超时
|
|
470
|
+
});
|
|
471
|
+
if (res.code === 200 && res.data?.code === 200) {
|
|
472
|
+
try {
|
|
473
|
+
console.log('网页登录成功');
|
|
474
|
+
return;
|
|
475
|
+
} catch (error) {
|
|
476
|
+
console.log('登录失败', error);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
console.log('登录失败', res);
|
|
481
|
+
}
|
|
434
482
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Query } from '@kevisual/query/query';
|
|
2
|
+
import { QueryRouterServer, Route } from '@kevisual/router/src/route.ts';
|
|
3
|
+
export class QueryProxy {
|
|
4
|
+
query: Query;
|
|
5
|
+
router: QueryRouterServer;
|
|
6
|
+
token?: string;
|
|
7
|
+
constructor(opts?: { query: Query, router?: QueryRouterServer, token?: string }) {
|
|
8
|
+
this.query = opts?.query || new Query();
|
|
9
|
+
this.router = opts?.router || new QueryRouterServer();
|
|
10
|
+
this.token = opts?.token;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 初始化路由
|
|
14
|
+
* @returns
|
|
15
|
+
*/
|
|
16
|
+
async init() {
|
|
17
|
+
const that = this;
|
|
18
|
+
const res = await this.query.post<{ list: RouterItem[] }>({ path: "router", key: 'list', token: this.token });
|
|
19
|
+
if (res.code !== 200) {
|
|
20
|
+
console.error('Failed to init query proxy router:', res.message);
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
const _list = res.data?.list || []
|
|
24
|
+
for (const item of _list) {
|
|
25
|
+
if (item.path && item.key) {
|
|
26
|
+
console.log(`Register route: [${item.path}] ${item.key}`);
|
|
27
|
+
this.router.route({
|
|
28
|
+
path: item.path,
|
|
29
|
+
key: item.key,
|
|
30
|
+
description: item.description,
|
|
31
|
+
metadata: item.metadata,
|
|
32
|
+
}).define(async (ctx) => {
|
|
33
|
+
const msg = { ...ctx.query };
|
|
34
|
+
if (msg.token === undefined && that.token !== undefined) {
|
|
35
|
+
msg.token = that.token;
|
|
36
|
+
}
|
|
37
|
+
const r = await that.query.post<any>({ path: item.path, key: item.key, ...msg });
|
|
38
|
+
ctx.forward(r)
|
|
39
|
+
}).addTo(that.router);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 列出路由
|
|
45
|
+
* @param filter
|
|
46
|
+
* @returns
|
|
47
|
+
*/
|
|
48
|
+
async listRoutes(filter?: (item: Route) => boolean) {
|
|
49
|
+
return this.router.routes.filter(filter || (() => true));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* 运行路由
|
|
53
|
+
* @param msg
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
async run(msg: { id?: string, path?: string, key?: string }) {
|
|
57
|
+
return await this.router.run(msg);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type RouterItem = {
|
|
62
|
+
id?: string;
|
|
63
|
+
path?: string;
|
|
64
|
+
key?: string;
|
|
65
|
+
description?: string;
|
|
66
|
+
middleware?: string[];
|
|
67
|
+
metadata?: Record<string, any>;
|
|
68
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 配置查询
|
|
3
|
+
* @updatedAt 2025-12-03 10:33:00
|
|
4
|
+
*/
|
|
5
|
+
import { Query } from '@kevisual/query';
|
|
6
|
+
type QueryConfigOpts = {
|
|
7
|
+
query?: Query;
|
|
8
|
+
};
|
|
9
|
+
export type Config<T = any> = {
|
|
10
|
+
id?: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
key?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
data?: T;
|
|
15
|
+
createdAt?: string;
|
|
16
|
+
updatedAt?: string;
|
|
17
|
+
};
|
|
18
|
+
export type UploadConfig = {
|
|
19
|
+
key?: string;
|
|
20
|
+
version?: string;
|
|
21
|
+
};
|
|
22
|
+
type PostOpts = {
|
|
23
|
+
token?: string;
|
|
24
|
+
payload?: Record<string, any>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export class QueryConfig {
|
|
28
|
+
query: Query;
|
|
29
|
+
constructor(opts?: QueryConfigOpts) {
|
|
30
|
+
this.query = opts?.query || new Query();
|
|
31
|
+
}
|
|
32
|
+
async post<T = Config>(data: any) {
|
|
33
|
+
return this.query.post<T>({ path: 'secret', ...data });
|
|
34
|
+
}
|
|
35
|
+
async getItem({ id, key }: { id?: string; key?: string }, opts?: PostOpts) {
|
|
36
|
+
return this.post({
|
|
37
|
+
key: 'get',
|
|
38
|
+
data: {
|
|
39
|
+
id,
|
|
40
|
+
key,
|
|
41
|
+
},
|
|
42
|
+
...opts,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
async updateItem(data: Config, opts?: PostOpts) {
|
|
46
|
+
return this.post({
|
|
47
|
+
key: 'update',
|
|
48
|
+
data,
|
|
49
|
+
...opts,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
async deleteItem(data: { id?: string, key?: string }, opts?: PostOpts) {
|
|
53
|
+
return this.post({
|
|
54
|
+
key: 'delete',
|
|
55
|
+
data,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async listItems(opts?: PostOpts) {
|
|
59
|
+
return this.post<{ list: Config[] }>({
|
|
60
|
+
key: 'list',
|
|
61
|
+
...opts,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -4,14 +4,13 @@ import { BaseQuery, DataOpts, Query } from '@kevisual/query/query';
|
|
|
4
4
|
|
|
5
5
|
export { shopDefine };
|
|
6
6
|
|
|
7
|
-
export class QueryShop<T extends Query = Query> extends BaseQuery<T
|
|
7
|
+
export class QueryShop<T extends Query = Query> extends BaseQuery<T> {
|
|
8
8
|
constructor(opts?: { query: T }) {
|
|
9
9
|
super({
|
|
10
10
|
query: opts?.query!,
|
|
11
|
-
queryDefine: shopDefine,
|
|
12
11
|
});
|
|
13
12
|
}
|
|
14
13
|
getInstall(data: any, opts?: DataOpts) {
|
|
15
|
-
return this.
|
|
14
|
+
return this.query.post(data, opts);
|
|
16
15
|
}
|
|
17
16
|
}
|
|
@@ -5,7 +5,8 @@ import { UploadProgress } from './core/upload-progress.ts';
|
|
|
5
5
|
|
|
6
6
|
export { uploadFiles, uploadFileChunked, UploadProgress };
|
|
7
7
|
|
|
8
|
-
export
|
|
8
|
+
export { toTextFile, toFile, getDirectoryAndName } from './utils/to-file.ts';
|
|
9
|
+
|
|
9
10
|
export { randomId } from './utils/random-id.ts';
|
|
10
11
|
|
|
11
12
|
export { filterFiles } from './utils/filter-files.ts';
|
package/readme.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# @kevisual/api
|
|
2
|
+
|
|
3
|
+
对 kevisual 相关的query router 的模块整理
|
|
4
|
+
|
|
5
|
+
包含的模块:
|
|
6
|
+
|
|
7
|
+
## query-config - 配置管理模块
|
|
8
|
+
|
|
9
|
+
提供配置的增删改查功能,支持默认配置项管理。
|
|
10
|
+
|
|
11
|
+
**主要功能:**
|
|
12
|
+
- 配置的获取、更新、删除
|
|
13
|
+
- 上传配置管理
|
|
14
|
+
- 默认配置项支持(upload.json, workspace.json, ai.json, user.json, life.json)
|
|
15
|
+
- 配置检测功能
|
|
16
|
+
|
|
17
|
+
**使用示例:**
|
|
18
|
+
```typescript
|
|
19
|
+
import { QueryConfig } from './query-config/query-config';
|
|
20
|
+
|
|
21
|
+
const config = new QueryConfig();
|
|
22
|
+
await config.getConfig({ key: 'upload.json' });
|
|
23
|
+
await config.updateConfig({ key: 'config.json', data: { setting: true } });
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## query-secret - 密钥管理模块
|
|
27
|
+
|
|
28
|
+
用于管理敏感信息和密钥的存储与检索。
|
|
29
|
+
|
|
30
|
+
**主要功能:**
|
|
31
|
+
- 密钥的存储和获取
|
|
32
|
+
- 支持按ID或key检索
|
|
33
|
+
- 密钥列表管理
|
|
34
|
+
|
|
35
|
+
## query-proxy - 代理路由模块
|
|
36
|
+
|
|
37
|
+
提供动态路由代理功能,可以将请求转发到不同的后端服务。
|
|
38
|
+
|
|
39
|
+
**主要功能:**
|
|
40
|
+
- 动态路由注册
|
|
41
|
+
- 请求转发代理
|
|
42
|
+
- 路由列表管理
|
|
43
|
+
- Token认证支持
|
|
44
|
+
|
|
45
|
+
**使用示例:**
|
|
46
|
+
```typescript
|
|
47
|
+
import { QueryProxy } from './query-proxy/index';
|
|
48
|
+
|
|
49
|
+
const proxy = new QueryProxy({
|
|
50
|
+
query: new Query(),
|
|
51
|
+
token: 'your-token'
|
|
52
|
+
});
|
|
53
|
+
await proxy.init(); // 初始化路由
|
|
54
|
+
const result = await proxy.run({ path: 'api', key: 'getData' });
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## query-upload - 文件上传模块
|
|
58
|
+
|
|
59
|
+
功能完整的文件上传解决方案,支持多种上传方式。
|
|
60
|
+
|
|
61
|
+
**主要功能:**
|
|
62
|
+
- 普通文件上传
|
|
63
|
+
- 分片上传(大文件)
|
|
64
|
+
- 上传进度跟踪
|
|
65
|
+
- 文件过滤工具
|
|
66
|
+
- 文件格式转换
|
|
67
|
+
|
|
68
|
+
**核心组件:**
|
|
69
|
+
- `uploadFiles` - 基础文件上传
|
|
70
|
+
- `uploadFileChunked` - 分片上传
|
|
71
|
+
- `UploadProgress` - 进度管理
|
|
72
|
+
- `filterFiles` - 文件过滤
|
|
73
|
+
- `toFile` - 格式转换
|
|
74
|
+
|
|
75
|
+
**使用示例:**
|
|
76
|
+
```typescript
|
|
77
|
+
import { uploadFiles, UploadProgress } from './query-upload/query-upload';
|
|
78
|
+
|
|
79
|
+
const progress = new UploadProgress();
|
|
80
|
+
await uploadFiles(files, {
|
|
81
|
+
onProgress: (loaded, total) => {
|
|
82
|
+
console.log(`上传进度: ${loaded}/${total}`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## query-app - 应用管理模块
|
|
88
|
+
|
|
89
|
+
管理应用的注册、获取和列表功能。
|
|
90
|
+
|
|
91
|
+
**主要功能:**
|
|
92
|
+
- 获取应用列表
|
|
93
|
+
- 获取公开应用
|
|
94
|
+
- 获取私有应用
|
|
95
|
+
- 应用定义管理
|
|
96
|
+
|
|
97
|
+
## query-shop - 应用商店模块
|
|
98
|
+
|
|
99
|
+
应用商店功能,处理应用的安装和获取。
|
|
100
|
+
|
|
101
|
+
**主要功能:**
|
|
102
|
+
- 应用安装
|
|
103
|
+
- 商店应用管理
|
|
104
|
+
|
|
105
|
+
## query-ai - AI对话模块
|
|
106
|
+
|
|
107
|
+
集成AI聊天功能,支持多种模型和对话管理。
|
|
108
|
+
|
|
109
|
+
**主要功能:**
|
|
110
|
+
- AI对话(支持GPT等模型)
|
|
111
|
+
- 模型列表获取
|
|
112
|
+
- 聊天使用统计
|
|
113
|
+
- 缓存管理
|
|
114
|
+
- 使用限制管理
|
|
115
|
+
|
|
116
|
+
**使用示例:**
|
|
117
|
+
```typescript
|
|
118
|
+
import { QueryAI } from './query-ai/query-ai';
|
|
119
|
+
|
|
120
|
+
const ai = new QueryAI({ query: new Query() });
|
|
121
|
+
const models = await ai.getModelList();
|
|
122
|
+
const response = await ai.chat(
|
|
123
|
+
{ message: '你好' },
|
|
124
|
+
{ username: 'user', model: 'gpt-3.5', group: 'default' }
|
|
125
|
+
);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## query-login - 登录认证模块
|
|
129
|
+
|
|
130
|
+
完整的登录认证解决方案,支持token管理和缓存。
|
|
131
|
+
|
|
132
|
+
**主要功能:**
|
|
133
|
+
- 用户登录认证
|
|
134
|
+
- Token管理(access/refresh token)
|
|
135
|
+
- 登录状态缓存
|
|
136
|
+
- 浏览器/Node.js环境支持
|
|
137
|
+
- 自动token刷新
|
|
138
|
+
|
|
139
|
+
**核心组件:**
|
|
140
|
+
- `QueryLogin` - 主登录类
|
|
141
|
+
- `LoginCacheStore` - 登录缓存
|
|
142
|
+
- `Cache` - 通用缓存接口
|
|
143
|
+
|
|
144
|
+
## query-resources - 资源管理模块
|
|
145
|
+
|
|
146
|
+
管理用户资源的访问和获取。
|
|
147
|
+
|
|
148
|
+
**主要功能:**
|
|
149
|
+
- 资源文件获取
|
|
150
|
+
- 资源列表管理
|
|
151
|
+
- 用户认证支持
|
|
152
|
+
- 文件预览功能
|
|
153
|
+
|
|
154
|
+
**使用示例:**
|
|
155
|
+
```typescript
|
|
156
|
+
import { QueryResources } from './query-resources/index';
|
|
157
|
+
|
|
158
|
+
const resources = new QueryResources({ username: 'user' });
|
|
159
|
+
const fileList = await resources.getList('images/');
|
|
160
|
+
const fileContent = await resources.fetchFile('document.pdf');
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## 架构特点
|
|
164
|
+
|
|
165
|
+
- **模块化设计**:每个模块职责单一,可独立使用
|
|
166
|
+
- **统一接口**:基于 `@kevisual/query` 的统一查询接口
|
|
167
|
+
- **环境兼容**:支持浏览器和Node.js环境
|
|
168
|
+
- **类型安全**:完整的TypeScript类型定义
|
|
169
|
+
- **扩展性**:易于扩展和自定义
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { Query } from '@kevisual/query';
|
|
2
|
-
import type { Result, DataOpts } from '@kevisual/query/query';
|
|
3
|
-
|
|
4
|
-
export type SimpleObject = Record<string, any>;
|
|
5
|
-
export const markType = ['simple', 'md', 'mdx', 'wallnote', 'excalidraw', 'chat'] as const;
|
|
6
|
-
export type MarkType = (typeof markType)[number];
|
|
7
|
-
export type MarkData = {
|
|
8
|
-
nodes?: any[];
|
|
9
|
-
edges?: any[];
|
|
10
|
-
elements?: any[];
|
|
11
|
-
permission?: any;
|
|
12
|
-
|
|
13
|
-
[key: string]: any;
|
|
14
|
-
};
|
|
15
|
-
export type Mark = {
|
|
16
|
-
id: string;
|
|
17
|
-
title: string;
|
|
18
|
-
description: string;
|
|
19
|
-
markType: MarkType;
|
|
20
|
-
link: string;
|
|
21
|
-
data?: MarkData;
|
|
22
|
-
uid: string;
|
|
23
|
-
puid: string;
|
|
24
|
-
summary: string;
|
|
25
|
-
thumbnail?: string;
|
|
26
|
-
tags: string[];
|
|
27
|
-
createdAt: string;
|
|
28
|
-
updatedAt: string;
|
|
29
|
-
version: number;
|
|
30
|
-
};
|
|
31
|
-
export type ShowMarkPick = Pick<Mark, 'id' | 'title' | 'description' | 'summary' | 'link' | 'tags' | 'thumbnail' | 'updatedAt'>;
|
|
32
|
-
|
|
33
|
-
export type SearchOpts = {
|
|
34
|
-
page?: number;
|
|
35
|
-
pageSize?: number;
|
|
36
|
-
search?: string;
|
|
37
|
-
sort?: string; // DESC, ASC
|
|
38
|
-
markType?: MarkType; // 类型
|
|
39
|
-
[key: string]: any;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export type QueryMarkOpts<T extends SimpleObject = SimpleObject> = {
|
|
43
|
-
query?: Query;
|
|
44
|
-
isBrowser?: boolean;
|
|
45
|
-
onLoad?: () => void;
|
|
46
|
-
} & T;
|
|
47
|
-
|
|
48
|
-
export type ResultMarkList = {
|
|
49
|
-
list: Mark[];
|
|
50
|
-
pagination: {
|
|
51
|
-
pageSize: number;
|
|
52
|
-
current: number;
|
|
53
|
-
total: number;
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
export type QueryMarkData = {
|
|
57
|
-
id?: string;
|
|
58
|
-
title?: string;
|
|
59
|
-
description?: string;
|
|
60
|
-
[key: string]: any;
|
|
61
|
-
};
|
|
62
|
-
export type QueryMarkResult = {
|
|
63
|
-
accessToken: string;
|
|
64
|
-
refreshToken: string;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export class QueryMarkBase<T extends SimpleObject = SimpleObject> {
|
|
68
|
-
query: Query;
|
|
69
|
-
isBrowser: boolean;
|
|
70
|
-
load?: boolean;
|
|
71
|
-
storage?: Storage;
|
|
72
|
-
onLoad?: () => void;
|
|
73
|
-
|
|
74
|
-
constructor(opts?: QueryMarkOpts<T>) {
|
|
75
|
-
this.query = opts?.query || new Query();
|
|
76
|
-
this.isBrowser = opts?.isBrowser ?? true;
|
|
77
|
-
this.init();
|
|
78
|
-
this.onLoad = opts?.onLoad;
|
|
79
|
-
}
|
|
80
|
-
setQuery(query: Query) {
|
|
81
|
-
this.query = query;
|
|
82
|
-
}
|
|
83
|
-
private async init() {
|
|
84
|
-
this.load = true;
|
|
85
|
-
this.onLoad?.();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async post<T = Result<any>>(data: any, opts?: DataOpts): Promise<T> {
|
|
89
|
-
try {
|
|
90
|
-
return this.query.post({ path: 'mark', ...data }, opts) as Promise<T>;
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.log('error', error);
|
|
93
|
-
return {
|
|
94
|
-
code: 400,
|
|
95
|
-
} as any;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async getMarkList(search: SearchOpts, opts?: DataOpts) {
|
|
100
|
-
return this.post<Result<ResultMarkList>>({ key: 'list', ...search }, opts);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async getMark(id: string, opts?: DataOpts) {
|
|
104
|
-
return this.post<Result<Mark>>({ key: 'get', id }, opts);
|
|
105
|
-
}
|
|
106
|
-
async getVersion(id: string, opts?: DataOpts) {
|
|
107
|
-
return this.post<Result<{ version: number; id: string }>>({ key: 'getVersion', id }, opts);
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* 检查版本
|
|
111
|
-
* 当需要更新时,返回true
|
|
112
|
-
* @param id
|
|
113
|
-
* @param version
|
|
114
|
-
* @param opts
|
|
115
|
-
* @returns
|
|
116
|
-
*/
|
|
117
|
-
async checkVersion(id: string, version?: number, opts?: DataOpts) {
|
|
118
|
-
if (!version) {
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
const res = await this.getVersion(id, opts);
|
|
122
|
-
if (res.code === 200) {
|
|
123
|
-
if (res.data!.version > version) {
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
return true;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async updateMark(data: any, opts?: DataOpts) {
|
|
132
|
-
return this.post<Result<Mark>>({ key: 'update', data }, opts);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async deleteMark(id: string, opts?: DataOpts) {
|
|
136
|
-
return this.post<Result<Mark>>({ key: 'delete', id }, opts);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
export class QueryMark extends QueryMarkBase<SimpleObject> {
|
|
140
|
-
markType: string;
|
|
141
|
-
constructor(opts?: QueryMarkOpts & { markType?: MarkType }) {
|
|
142
|
-
super(opts);
|
|
143
|
-
this.markType = opts?.markType || 'simple';
|
|
144
|
-
}
|
|
145
|
-
async getMarkList(search?: SearchOpts, opts?: DataOpts) {
|
|
146
|
-
return this.post<Result<ResultMarkList>>({ key: 'list', ...search, markType: this.markType }, opts);
|
|
147
|
-
}
|
|
148
|
-
async updateMark(data: any, opts?: DataOpts) {
|
|
149
|
-
if (!data.id) {
|
|
150
|
-
data.markType = this.markType || 'simple';
|
|
151
|
-
}
|
|
152
|
-
return super.updateMark(data, opts);
|
|
153
|
-
}
|
|
154
|
-
}
|