init
This commit is contained in:
28
package.json
28
package.json
@@ -1,31 +1,37 @@
|
|||||||
{
|
{
|
||||||
"name": "@kevisual/query-awesome",
|
"name": "@kevisual/api",
|
||||||
"version": "0.0.4",
|
"version": "0.0.5",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "mod.ts",
|
"main": "mod.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "turbo run build",
|
"build": "bun run bun.config.ts",
|
||||||
"postbuild": "bun bun.copy.config.mjs"
|
"postbuild": "bun bun.copy.config.mjs"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist",
|
||||||
|
"query",
|
||||||
|
"mod.ts"
|
||||||
],
|
],
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"packageManager": "pnpm@10.24.0",
|
"packageManager": "pnpm@10.26.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kevisual/query": "^0.0.31",
|
"@kevisual/query": "^0.0.33",
|
||||||
"@kevisual/router": "^0.0.36",
|
"@kevisual/router": "^0.0.41",
|
||||||
"@kevisual/types": "^0.0.10",
|
"@kevisual/types": "^0.0.10",
|
||||||
"@kevisual/use-config": "^1.0.21",
|
"@kevisual/use-config": "^1.0.21",
|
||||||
"@types/bun": "^1.3.3",
|
"@types/bun": "^1.3.5",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^25.0.3",
|
||||||
"fast-glob": "^3.3.3",
|
"dotenv": "^17.2.3",
|
||||||
"tsup": "^8.5.1"
|
"fast-glob": "^3.3.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"es-toolkit": "^1.43.0",
|
||||||
|
"nanoid": "^5.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1179
pnpm-lock.yaml
generated
1179
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,27 +1,21 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://kevisual.xiongxiao.me/root/ai/kevisual/tools/kevisual-sync/schema.json?v=2",
|
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
"name": "kevisual",
|
||||||
"share": "public"
|
"share": "public"
|
||||||
},
|
},
|
||||||
"checkDir": {
|
"registry": "https://kevisual.cn/root/ai/kevisual/common/query/api",
|
||||||
"src/query": {
|
"clone": {
|
||||||
"url": "https://kevisual.cn/root/ai/code/template/registry/query",
|
".": {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"syncDirectory": [
|
"syncd": [
|
||||||
{
|
{
|
||||||
"files": [
|
"files": [
|
||||||
"**/*"
|
"**/*"
|
||||||
],
|
],
|
||||||
"ignore": [],
|
"registry": ""
|
||||||
"registry": "https://kevisual.cn/root/ai/code/template/registry/query"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"sync": {
|
"sync": {}
|
||||||
"kevisual.json": {
|
|
||||||
"url": "https://kevisual.cn/root/ai/code/template/registry/query/kevisual.json",
|
|
||||||
"type": "none"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
68
query/query-proxy/index.ts
Normal file
68
query/query-proxy/index.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import { Query } from '@kevisual/query/query';
|
||||||
|
import { QueryRouterServer, Route } from '@kevisual/router/src/route.ts';
|
||||||
|
export class QueryProxy {
|
||||||
|
query: Query;
|
||||||
|
router: QueryRouterServer;
|
||||||
|
token?: string;
|
||||||
|
constructor(opts?: { query: Query, router?: QueryRouterServer, token?: string }) {
|
||||||
|
this.query = opts?.query || new Query();
|
||||||
|
this.router = opts?.router || new QueryRouterServer();
|
||||||
|
this.token = opts?.token;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 初始化路由
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async init() {
|
||||||
|
const that = this;
|
||||||
|
const res = await this.query.post<{ list: RouterItem[] }>({ path: "router", key: 'list', token: this.token });
|
||||||
|
if (res.code !== 200) {
|
||||||
|
console.error('Failed to init query proxy router:', res.message);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const _list = res.data?.list || []
|
||||||
|
for (const item of _list) {
|
||||||
|
if (item.path && item.key) {
|
||||||
|
console.log(`Register route: [${item.path}] ${item.key}`);
|
||||||
|
this.router.route({
|
||||||
|
path: item.path,
|
||||||
|
key: item.key,
|
||||||
|
description: item.description,
|
||||||
|
metadata: item.metadata,
|
||||||
|
}).define(async (ctx) => {
|
||||||
|
const msg = { ...ctx.query };
|
||||||
|
if (msg.token === undefined && that.token !== undefined) {
|
||||||
|
msg.token = that.token;
|
||||||
|
}
|
||||||
|
const r = await that.query.post<any>({ path: item.path, key: item.key, ...msg });
|
||||||
|
ctx.forward(r)
|
||||||
|
}).addTo(that.router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 列出路由
|
||||||
|
* @param filter
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async listRoutes(filter?: (item: Route) => boolean) {
|
||||||
|
return this.router.routes.filter(filter || (() => true));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 运行路由
|
||||||
|
* @param msg
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async run(msg: { id?: string, path?: string, key?: string }) {
|
||||||
|
return await this.router.run(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RouterItem = {
|
||||||
|
id?: string;
|
||||||
|
path?: string;
|
||||||
|
key?: string;
|
||||||
|
description?: string;
|
||||||
|
middleware?: string[];
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
* @updatedAt 2025-12-03 10:33:00
|
* @updatedAt 2025-12-03 10:33:00
|
||||||
*/
|
*/
|
||||||
import { Query } from '@kevisual/query';
|
import { Query } from '@kevisual/query';
|
||||||
import type { Result } from '@kevisual/query/query';
|
|
||||||
type QueryConfigOpts = {
|
type QueryConfigOpts = {
|
||||||
query?: Query;
|
query?: Query;
|
||||||
};
|
};
|
||||||
|
|||||||
168
readme.md
168
readme.md
@@ -1,3 +1,169 @@
|
|||||||
# query-awesome
|
# @kevisual/api
|
||||||
|
|
||||||
对 kevisual 相关的query router 的模块整理
|
对 kevisual 相关的query router 的模块整理
|
||||||
|
|
||||||
|
包含的模块:
|
||||||
|
|
||||||
|
## query-config - 配置管理模块
|
||||||
|
|
||||||
|
提供配置的增删改查功能,支持默认配置项管理。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- 配置的获取、更新、删除
|
||||||
|
- 上传配置管理
|
||||||
|
- 默认配置项支持(upload.json, workspace.json, ai.json, user.json, life.json)
|
||||||
|
- 配置检测功能
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```typescript
|
||||||
|
import { QueryConfig } from './query-config/query-config';
|
||||||
|
|
||||||
|
const config = new QueryConfig();
|
||||||
|
await config.getConfig({ key: 'upload.json' });
|
||||||
|
await config.updateConfig({ key: 'config.json', data: { setting: true } });
|
||||||
|
```
|
||||||
|
|
||||||
|
## query-secret - 密钥管理模块
|
||||||
|
|
||||||
|
用于管理敏感信息和密钥的存储与检索。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- 密钥的存储和获取
|
||||||
|
- 支持按ID或key检索
|
||||||
|
- 密钥列表管理
|
||||||
|
|
||||||
|
## query-proxy - 代理路由模块
|
||||||
|
|
||||||
|
提供动态路由代理功能,可以将请求转发到不同的后端服务。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- 动态路由注册
|
||||||
|
- 请求转发代理
|
||||||
|
- 路由列表管理
|
||||||
|
- Token认证支持
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```typescript
|
||||||
|
import { QueryProxy } from './query-proxy/index';
|
||||||
|
|
||||||
|
const proxy = new QueryProxy({
|
||||||
|
query: new Query(),
|
||||||
|
token: 'your-token'
|
||||||
|
});
|
||||||
|
await proxy.init(); // 初始化路由
|
||||||
|
const result = await proxy.run({ path: 'api', key: 'getData' });
|
||||||
|
```
|
||||||
|
|
||||||
|
## query-upload - 文件上传模块
|
||||||
|
|
||||||
|
功能完整的文件上传解决方案,支持多种上传方式。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- 普通文件上传
|
||||||
|
- 分片上传(大文件)
|
||||||
|
- 上传进度跟踪
|
||||||
|
- 文件过滤工具
|
||||||
|
- 文件格式转换
|
||||||
|
|
||||||
|
**核心组件:**
|
||||||
|
- `uploadFiles` - 基础文件上传
|
||||||
|
- `uploadFileChunked` - 分片上传
|
||||||
|
- `UploadProgress` - 进度管理
|
||||||
|
- `filterFiles` - 文件过滤
|
||||||
|
- `toFile` - 格式转换
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```typescript
|
||||||
|
import { uploadFiles, UploadProgress } from './query-upload/query-upload';
|
||||||
|
|
||||||
|
const progress = new UploadProgress();
|
||||||
|
await uploadFiles(files, {
|
||||||
|
onProgress: (loaded, total) => {
|
||||||
|
console.log(`上传进度: ${loaded}/${total}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## query-app - 应用管理模块
|
||||||
|
|
||||||
|
管理应用的注册、获取和列表功能。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- 获取应用列表
|
||||||
|
- 获取公开应用
|
||||||
|
- 获取私有应用
|
||||||
|
- 应用定义管理
|
||||||
|
|
||||||
|
## query-shop - 应用商店模块
|
||||||
|
|
||||||
|
应用商店功能,处理应用的安装和获取。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- 应用安装
|
||||||
|
- 商店应用管理
|
||||||
|
|
||||||
|
## query-ai - AI对话模块
|
||||||
|
|
||||||
|
集成AI聊天功能,支持多种模型和对话管理。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- AI对话(支持GPT等模型)
|
||||||
|
- 模型列表获取
|
||||||
|
- 聊天使用统计
|
||||||
|
- 缓存管理
|
||||||
|
- 使用限制管理
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```typescript
|
||||||
|
import { QueryAI } from './query-ai/query-ai';
|
||||||
|
|
||||||
|
const ai = new QueryAI({ query: new Query() });
|
||||||
|
const models = await ai.getModelList();
|
||||||
|
const response = await ai.chat(
|
||||||
|
{ message: '你好' },
|
||||||
|
{ username: 'user', model: 'gpt-3.5', group: 'default' }
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## query-login - 登录认证模块
|
||||||
|
|
||||||
|
完整的登录认证解决方案,支持token管理和缓存。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- 用户登录认证
|
||||||
|
- Token管理(access/refresh token)
|
||||||
|
- 登录状态缓存
|
||||||
|
- 浏览器/Node.js环境支持
|
||||||
|
- 自动token刷新
|
||||||
|
|
||||||
|
**核心组件:**
|
||||||
|
- `QueryLogin` - 主登录类
|
||||||
|
- `LoginCacheStore` - 登录缓存
|
||||||
|
- `Cache` - 通用缓存接口
|
||||||
|
|
||||||
|
## query-resources - 资源管理模块
|
||||||
|
|
||||||
|
管理用户资源的访问和获取。
|
||||||
|
|
||||||
|
**主要功能:**
|
||||||
|
- 资源文件获取
|
||||||
|
- 资源列表管理
|
||||||
|
- 用户认证支持
|
||||||
|
- 文件预览功能
|
||||||
|
|
||||||
|
**使用示例:**
|
||||||
|
```typescript
|
||||||
|
import { QueryResources } from './query-resources/index';
|
||||||
|
|
||||||
|
const resources = new QueryResources({ username: 'user' });
|
||||||
|
const fileList = await resources.getList('images/');
|
||||||
|
const fileContent = await resources.fetchFile('document.pdf');
|
||||||
|
```
|
||||||
|
|
||||||
|
## 架构特点
|
||||||
|
|
||||||
|
- **模块化设计**:每个模块职责单一,可独立使用
|
||||||
|
- **统一接口**:基于 `@kevisual/query` 的统一查询接口
|
||||||
|
- **环境兼容**:支持浏览器和Node.js环境
|
||||||
|
- **类型安全**:完整的TypeScript类型定义
|
||||||
|
- **扩展性**:易于扩展和自定义
|
||||||
|
|||||||
28
test/proxy.ts
Normal file
28
test/proxy.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { QueryProxy } from "../query/query-proxy";
|
||||||
|
import { Query } from "@kevisual/query/query";
|
||||||
|
import dotenv from "dotenv";
|
||||||
|
import util from 'node:util'
|
||||||
|
dotenv.config();
|
||||||
|
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
|
|
||||||
|
const token = process.env.KEVISUAL_TOKEN;
|
||||||
|
const url = process.env.KEVISUAL_URL;
|
||||||
|
export const showMore = (obj: any) => {
|
||||||
|
return util.inspect(obj, { showHidden: false, depth: null, colors: true });
|
||||||
|
}
|
||||||
|
const query = new Query({ url: url + '/api/router' });
|
||||||
|
const proxy = new QueryProxy({ query, token });
|
||||||
|
const res = await proxy.init();
|
||||||
|
|
||||||
|
console.log('Proxy Init Result:', showMore(res));
|
||||||
|
|
||||||
|
const routes = await proxy.listRoutes((item) => item.path?.startsWith('router') || false);
|
||||||
|
console.log('Filtered Routes:', showMore(routes));
|
||||||
|
|
||||||
|
await sleep(1000);
|
||||||
|
|
||||||
|
// console.log('Running route [user/me]...', proxy.router.routes.length);
|
||||||
|
|
||||||
|
const run = await proxy.run({ path: 'user', key: 'me' });
|
||||||
|
// const run = await proxy.run({ path: 'router', key: 'list' });
|
||||||
|
console.log('Run Result:', showMore(run));
|
||||||
Reference in New Issue
Block a user