Compare commits

..

5 Commits

Author SHA1 Message Date
03be62cfe6 feat: 重命名代理响应流传输函数,增强代码可读性 2025-12-21 14:19:57 +08:00
f12fea7246 feat: 更新依赖项版本,增强代理请求处理逻辑,调整 WebSocket 路由和 API 代理配置 2025-12-21 06:40:16 +08:00
8007315c66 feat: 更新 WebSocket 路由,添加缺失的路由配置并调整测试用例 2025-12-21 04:42:36 +08:00
11ac3f9de9 feat: 增强流管道功能,添加 Bun 环境支持,重构代理请求和响应处理逻辑 2025-12-21 04:37:07 +08:00
36628c8279 feat: update WebSocket connection and add system version sending functionality
- Changed WebSocket connection URL to localhost for testing.
- Added a function to send system version to the server upon connection and after a delay.
- Improved logging for received messages.

chore: update package dependencies

- Bump versions for several dependencies including @kevisual/query, lucide-react, vue, and others.
- Update package manager version to pnpm@10.26.1.

fix: adjust app initialization to use sessionStorage

- Modified the app initialization to use a custom sessionStorage implementation backed by an LRU cache.

feat: implement sessionStorage with LRU cache

- Added a new module for sessionStorage that utilizes LRUCache for efficient caching.
2025-12-21 04:20:25 +08:00
15 changed files with 436 additions and 115 deletions

View File

@@ -10,7 +10,7 @@
],
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
"license": "MIT",
"packageManager": "pnpm@10.26.0",
"packageManager": "pnpm@10.26.1",
"type": "module",
"files": [
"dist",
@@ -46,12 +46,12 @@
"@kevisual/load": "^0.0.6",
"@kevisual/local-app-manager": "^0.1.32",
"@kevisual/logger": "^0.0.4",
"@kevisual/query": "0.0.32",
"@kevisual/query": "0.0.33",
"@kevisual/query-login": "0.0.7",
"@kevisual/router": "^0.0.39",
"@kevisual/router": "^0.0.48",
"@kevisual/types": "^0.0.10",
"@kevisual/use-config": "^1.0.21",
"@types/bun": "^1.3.4",
"@types/bun": "^1.3.5",
"@types/lodash-es": "^4.17.12",
"@types/node": "^25.0.3",
"@types/send": "^1.2.1",

View File

@@ -1,4 +1,5 @@
import { App } from '@kevisual/router';
// import { App } from '@kevisual/router/src/app.ts';
import { HttpsPem } from '@/module/assistant/https/sign.ts';
// import { AssistantConfig } from '@/module/assistant/index.ts';
import { AssistantInit, parseHomeArg } from '@/services/init/index.ts';
@@ -41,7 +42,8 @@ export const app: App = useContextKey<App>('app', () => {
httpType: 'http',
cors: {
origin: '*',
}
},
io: true
},
});
}
@@ -54,7 +56,8 @@ export const app: App = useContextKey<App>('app', () => {
httpsKey: httpsPem.key,
cors: {
origin: '*',
}
},
io: true
},
});
});

View File

@@ -2,11 +2,16 @@ import http from 'node:http';
import https from 'node:https';
import { rewriteCookieDomain } from '../https/cookie-rewrite.ts';
import { ProxyInfo } from './proxy.ts';
import { pipeProxyReq, pipeProxyRes, pipeStream } from './pipe.ts';
export const defaultApiProxy = [
{
path: '/api/router',
target: 'https://kevisual.cn',
},
{
path: '/api/s1',
target: 'https://kevisual.cn',
},
{
path: '/v1',
target: 'https://kevisual.cn',
@@ -99,7 +104,8 @@ export const httpProxy = (req: http.IncomingMessage, res: http.ServerResponse, p
// 将代理服务器的响应头和状态码返回给客户端
res.writeHead(proxyRes.statusCode, responseHeaders);
// 将代理响应流写入客户端响应
proxyRes.pipe(res, { end: true });
// proxyRes.pipe(res, { end: true });
pipeProxyRes(proxyRes, res);
});
// 处理代理请求的错误事件
proxyReq.on('error', (err) => {
@@ -108,6 +114,6 @@ export const httpProxy = (req: http.IncomingMessage, res: http.ServerResponse, p
res.write(`Proxy request error: ${err.message}`);
});
// 处理 POST 请求的请求体(传递数据到目标服务器),end:true 表示当请求体结束时,关闭请求
req.pipe(proxyReq, { end: true });
return;
};
// req.pipe(proxyReq, { end: true });
pipeProxyReq(req, proxyReq, res);
}

View File

@@ -2,4 +2,3 @@ export * from './proxy.ts';
export * from './file-proxy.ts';
export { default as send } from 'send';
export * from './http-proxy.ts';
export * from './ws-proxy.ts';

View File

@@ -0,0 +1,114 @@
import * as http from 'http';
import * as fs from 'fs';
import { isBun } from './utils.ts';
/**
* 文件流管道传输函数
* 将指定文件的内容通过流的方式传输给客户端响应
* @param filePath 要传输的文件路径
* @param res HTTP服务器响应对象
*/
export const pipeFileStream = (filePath: string, res: http.ServerResponse) => {
const readStream = fs.createReadStream(filePath);
if (isBun) {
// Bun环境下的流处理方式
res.pipe(readStream as any);
} else {
// Node.js标准环境下的流处理方式end:true表示在流结束时自动关闭响应
readStream.pipe(res, { end: true });
}
}
/**
* 通用流管道传输函数
* 将可读流的数据传输给客户端响应
* @param readStream 可读流对象
* @param res HTTP服务器响应对象
*/
export const pipeStream = (readStream: fs.ReadStream, res: http.ServerResponse) => {
if (isBun) {
// Bun环境下的流处理方式
res.pipe(readStream as any);
} else {
// Node.js标准环境下的流处理方式
readStream.pipe(res, { end: true });
}
}
/**
* 代理响应流传输函数
* 将代理服务器返回的响应数据传输给客户端
* 处理从目标服务器收到的响应流并转发给原始客户端
* @param proxyRes 代理服务器的响应对象
* @param res HTTP服务器响应对象
*/
export const pipeProxyRes = (proxyRes: http.IncomingMessage, res: http.ServerResponse) => {
if (isBun) {
// Bun环境下需要手动收集数据并end因为Bun的pipe机制与Node.js不同
const chunks: Buffer[] = [];
// 监听数据到达事件,收集所有数据块
proxyRes.on('data', (chunk: Buffer) => {
chunks.push(chunk);
});
if (proxyRes.url === '/api/router') {
console.log(proxyRes.url, proxyRes.statusCode);
}
// 监听数据结束事件,将收集的数据合并并发送给客户端
proxyRes.on('end', () => {
const result = Buffer.concat(chunks).toString();
res.end(result);
});
// 监听错误事件,处理代理响应过程中的错误
proxyRes.on('error', (error) => {
res.writeHead(500);
res.end(JSON.stringify({ error: error.message }));
});
} else {
// Node.js标准环境下直接使用pipe进行流传输
proxyRes.pipe(res, { end: true });
}
}
/**
* 代理请求流传输函数
* 将客户端的请求数据传输给代理服务器
* 处理来自客户端的请求流并转发给目标服务器
* @param req 客户端的请求对象
* @param proxyReq 代理服务器的请求对象
*/
export const pipeProxyReq = async (req: http.IncomingMessage, proxyReq: http.ClientRequest, res: any) => {
if (isBun) {
try {
// @ts-ignore
const bunRequest = req.bun.request;
const contentType = req.headers['content-type'] || '';
if (contentType.includes('multipart/form-data')) {
console.log('Processing multipart/form-data');
const arrayBuffer = await bunRequest.arrayBuffer();
// 设置请求头(在写入数据之前)
proxyReq.setHeader('content-type', contentType);
proxyReq.setHeader('content-length', arrayBuffer.byteLength.toString());
// 写入数据并结束请求
if (arrayBuffer.byteLength > 0) {
proxyReq.write(Buffer.from(arrayBuffer));
}
proxyReq.end();
return;
}
console.log('Bun pipeProxyReq content-type', contentType);
// @ts-ignore
const bodyString = req.body;
bodyString && proxyReq.write(bodyString);
proxyReq.end();
} catch (error) {
proxyReq.destroy(error);
}
} else {
// Node.js标准环境下直接使用pipe进行流传输
req.pipe(proxyReq, { end: true });
}
}

View File

@@ -0,0 +1,6 @@
export const isBun = typeof Bun !== 'undefined' && Bun?.version != null;
export const isNode = typeof process !== 'undefined' && process?.versions != null && process.versions?.node != null;
// @ts-ignore
export const isDeno = typeof Deno !== 'undefined' && Deno?.version != null && Deno?.version?.deno != null;

View File

@@ -4,6 +4,7 @@ import type { Http2Server } from 'node:http2';
import { WebSocket } from 'ws';
import { ProxyInfo } from './proxy.ts';
import { WebSocketServer } from 'ws';
import { isBun, isNode } from './utils.ts';
export const wss = new WebSocketServer({
noServer: true,
@@ -97,7 +98,13 @@ export const wsProxy = (server: HttpServer | HttpsServer | Http2Server, config:
await wssApp.handleConnection(ws, req);
});
// 处理升级请求
if (!isBun) {
server.on('upgrade', (request, socket, head) => {
wssApp.upgrade(request, socket, head);
});
} else if (isBun) {
// @ts-ignore
console.warn('Bun WebSocket proxy is not implemented yet.');
console.log('server', server)
}
};

View File

@@ -38,8 +38,12 @@ export const runServer = async (port: number = 51015, listenPath = '127.0.0.1')
console.log(`Server is running on ${protocol}://${listenPath}:${_port}`);
});
}
app.server.on(proxyRoute);
proxyWs();
app.server.on([{
id: 'handle-all',
func: proxyRoute as any,
},
...proxyWs()
]);
const manager = new AssistantApp(assistantConfig, app);
setTimeout(() => {
manager.load({ runtime: 'client' }).then(() => {

View File

@@ -1,10 +1,12 @@
import { fileProxy, httpProxy, createApiProxy, wsProxy } from '@/module/assistant/index.ts';
import { fileProxy, httpProxy, createApiProxy, ProxyInfo } from '@/module/assistant/index.ts';
import http from 'node:http';
import { LocalProxy } from './local-proxy.ts';
import { assistantConfig, app } from '@/app.ts';
import { log, logger } from '@/module/logger.ts';
import { getToken } from '@/module/http-token.ts';
import { getTokenUserCache } from '@/routes/index.ts';
import type { WebSocketListenerFun } from "@kevisual/router";
import WebSocket from 'ws';
const localProxy = new LocalProxy({});
localProxy.initFromAssistantConfig(assistantConfig);
@@ -173,10 +175,74 @@ export const proxyRoute = async (req: http.IncomingMessage, res: http.ServerResp
export const proxyWs = () => {
const apiProxy = assistantConfig.getCacheAssistantConfig()?.api?.proxy || [];
const registry = assistantConfig.getRegistry()
const proxy = assistantConfig.getCacheAssistantConfig()?.proxy || [];
const proxyApi = [...apiProxy, ...proxy].filter((item) => item.ws);
log.debug('proxyApi ', proxyApi);
wsProxy(app.server.server, {
apiList: proxyApi,
const demoProxy = [
{
path: '/api/ws/demo',
target: 'https://kevisual.xiongxiao.me',
pathname: '/api/router',
ws: true,
}
]
const pathRouter = proxyApi.find((item) => item.path === '/api/router');
if (!pathRouter) {
proxyApi.push({
path: '/api/router',
target: registry || 'https://kevisual.cn',
pathname: '/api/router',
ws: true,
});
}
return proxyApi.map(createProxyInfo);
};
export const createProxyInfo = (proxyApiItem: ProxyInfo) => {
const func: WebSocketListenerFun = async (req, res) => {
const { ws, emitter, id, data } = req;
if (!id) {
ws.send(JSON.stringify({ type: 'error', message: 'not found id' }));
ws.close();
return;
}
// @ts-ignore
let _proxySocket = ws.data.proxySocket;
if (!_proxySocket) {
const _u = new URL(proxyApiItem.path, `${proxyApiItem.target}`);
if (proxyApiItem.pathname) {
_u.pathname = proxyApiItem.pathname;
}
const isHttps = _u.protocol === 'https:';
const wsProtocol = isHttps ? 'wss' : 'ws';
const wsUrl = `${wsProtocol}://${_u.host}${_u.pathname}`;
console.log('WebSocket proxy URL', { wsUrl });
const proxySocket = new WebSocket(wsUrl);
proxySocket.on('open', () => {
proxySocket.on('message', (message) => {
ws.send(message);
});
});
proxySocket.on('error', (err) => {
console.error(`WebSocket proxy error: ${err.message}`);
});
proxySocket.on('close', () => {
console.log('WebSocket proxy closed');
});
emitter.once('close--' + id, () => {
console.log('WebSocket client closed');
proxySocket?.close?.();
});
// @ts-ignore
ws.data.proxySocket = proxySocket;
return;
}
console.log('ws.data', data);
_proxySocket.send(JSON.stringify(data))
}
return {
path: proxyApiItem.path,
io: true,
func: func
}
}

View File

@@ -5,11 +5,21 @@ const testRouter = () => {
// const ws = new WebSocket('wss://kevisual.xiongxiao.me/ws/proxy');
// const ws = new WebSocket('wss://kevisual.xiongxiao.me/api/router');
const ws = new WebSocket('ws://118.196.32.29:3005/api/router');
// const ws = new WebSocket('ws://118.196.32.29:3005/api/router');
// const ws = new WebSocket('wss://kevisual.cn/api/router');
// const ws = new WebSocket('ws://localhost:51015/api/ws/demo?id=12345');
const ws = new WebSocket('ws://localhost:51015/api/router?id=12345');
console.log('Connecting to WebSocket server...');
ws.on('open', () => {
console.log('WebSocket connection opened');
sendSystemVersion();
setTimeout(() => {
sendSystemVersion();
console.log('第二次发送');
}, 3000);
});
const sendSystemVersion = () => {
ws.send(
JSON.stringify({
"type": "router",
@@ -19,10 +29,10 @@ const testRouter = () => {
}
}),
);
});
}
ws.on('message', (data) => {
console.log('Received message from server:', data.toString());
console.log('Received message from server e:', data.toString());
});
ws.on('close', () => {
console.log('WebSocket connection closed');

View File

@@ -8,7 +8,7 @@
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"pub": "envision deploy ./dist -k cli -v 0.0.3 -u",
"pub": "envision deploy ./dist -k cli -v 0.0.3 -u -y y",
"slide:dev": "slidev --open slides/index.md",
"slide:build": "slidev build slides/index.md --base /root/cli-slide/",
"slide:pub": "envision deploy ./slides/dist -k cli-slide -v 0.0.3 -u",
@@ -26,7 +26,7 @@
"@kevisual/api": "^0.0.5",
"@kevisual/context": "^0.0.4",
"@kevisual/kv-code": "^0.0.4",
"@kevisual/query": "^0.0.32",
"@kevisual/query": "^0.0.33",
"@kevisual/query-login": "^0.0.7",
"@kevisual/registry": "^0.0.1",
"@radix-ui/react-slot": "^1.2.4",
@@ -40,7 +40,7 @@
"es-toolkit": "^1.43.0",
"github-markdown-css": "^5.8.1",
"highlight.js": "^11.11.1",
"lucide-react": "^0.561.0",
"lucide-react": "^0.562.0",
"marked": "^17.0.1",
"marked-highlight": "^2.2.3",
"nanoid": "^5.1.6",
@@ -48,7 +48,7 @@
"react-dom": "^19.2.3",
"react-toastify": "^11.0.5",
"tailwind-merge": "^3.4.0",
"vue": "^3.5.25",
"vue": "^3.5.26",
"zustand": "^5.0.9"
},
"publishConfig": {
@@ -62,7 +62,7 @@
"tailwindcss": "^4.1.18",
"tw-animate-css": "^1.4.0"
},
"packageManager": "pnpm@10.26.0",
"packageManager": "pnpm@10.26.1",
"onlyBuiltDependencies": [
"@tailwindcss/oxide",
"esbuild",

View File

@@ -41,7 +41,7 @@
],
"author": "abearxiong",
"dependencies": {
"@kevisual/app": "^0.0.1",
"@kevisual/app": "^0.0.2",
"@kevisual/context": "^0.0.4",
"@kevisual/hot-api": "^0.0.3",
"@nut-tree-fork/nut-js": "^4.2.6",
@@ -57,9 +57,9 @@
"@kevisual/dts": "^0.0.3",
"@kevisual/load": "^0.0.6",
"@kevisual/logger": "^0.0.4",
"@kevisual/query": "0.0.32",
"@kevisual/query": "0.0.33",
"@kevisual/query-login": "0.0.7",
"@types/bun": "^1.3.4",
"@types/bun": "^1.3.5",
"@types/crypto-js": "^4.2.2",
"@types/jsonwebtoken": "^9.0.10",
"@types/micromatch": "^4.0.10",

243
pnpm-lock.yaml generated
View File

@@ -9,8 +9,8 @@ importers:
.:
dependencies:
'@kevisual/app':
specifier: ^0.0.1
version: 0.0.1(dotenv@17.2.3)
specifier: ^0.0.2
version: 0.0.2(dotenv@17.2.3)
'@kevisual/context':
specifier: ^0.0.4
version: 0.0.4
@@ -52,14 +52,14 @@ importers:
specifier: ^0.0.4
version: 0.0.4
'@kevisual/query':
specifier: 0.0.32
version: 0.0.32
specifier: 0.0.33
version: 0.0.33
'@kevisual/query-login':
specifier: 0.0.7
version: 0.0.7(@kevisual/query@0.0.32)
version: 0.0.7(@kevisual/query@0.0.33)
'@types/bun':
specifier: ^1.3.4
version: 1.3.4
specifier: ^1.3.5
version: 1.3.5
'@types/crypto-js':
specifier: ^4.2.2
version: 4.2.2
@@ -140,14 +140,14 @@ importers:
specifier: ^0.0.4
version: 0.0.4
'@kevisual/query':
specifier: 0.0.32
version: 0.0.32
specifier: 0.0.33
version: 0.0.33
'@kevisual/query-login':
specifier: 0.0.7
version: 0.0.7(@kevisual/query@0.0.32)
version: 0.0.7(@kevisual/query@0.0.33)
'@kevisual/router':
specifier: ^0.0.39
version: 0.0.39(supports-color@10.2.2)
specifier: ^0.0.48
version: 0.0.48(supports-color@10.2.2)
'@kevisual/types':
specifier: ^0.0.10
version: 0.0.10
@@ -155,8 +155,8 @@ importers:
specifier: ^1.0.21
version: 1.0.21(dotenv@17.2.3)
'@types/bun':
specifier: ^1.3.4
version: 1.3.4
specifier: ^1.3.5
version: 1.3.5
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
@@ -219,7 +219,7 @@ importers:
version: 3.6.0
'@astrojs/vue':
specifier: ^5.1.3
version: 5.1.3(@types/node@25.0.3)(astro@5.16.6(@types/node@25.0.3)(idb-keyval@6.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2))(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(vue@3.5.25(typescript@5.8.2))
version: 5.1.3(@types/node@25.0.3)(astro@5.16.6(@types/node@25.0.3)(idb-keyval@6.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2))(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(vue@3.5.26(typescript@5.8.2))
'@kevisual/api':
specifier: ^0.0.5
version: 0.0.5
@@ -230,11 +230,11 @@ importers:
specifier: ^0.0.4
version: 0.0.4(@types/react@19.2.7)(dotenv@17.2.3)
'@kevisual/query':
specifier: ^0.0.32
version: 0.0.32
specifier: ^0.0.33
version: 0.0.33
'@kevisual/query-login':
specifier: ^0.0.7
version: 0.0.7(@kevisual/query@0.0.32)
version: 0.0.7(@kevisual/query@0.0.33)
'@kevisual/registry':
specifier: ^0.0.1
version: 0.0.1(typescript@5.8.2)
@@ -272,8 +272,8 @@ importers:
specifier: ^11.11.1
version: 11.11.1
lucide-react:
specifier: ^0.561.0
version: 0.561.0(react@19.2.3)
specifier: ^0.562.0
version: 0.562.0(react@19.2.3)
marked:
specifier: ^17.0.1
version: 17.0.1
@@ -296,8 +296,8 @@ importers:
specifier: ^3.4.0
version: 3.4.0
vue:
specifier: ^3.5.25
version: 3.5.25(typescript@5.8.2)
specifier: ^3.5.26
version: 3.5.26(typescript@5.8.2)
zustand:
specifier: ^5.0.9
version: 5.0.9(@types/react@19.2.7)(react@19.2.3)
@@ -1250,6 +1250,9 @@ packages:
'@kevisual/app@0.0.1':
resolution: {integrity: sha512-PEx8P3l0iNSqrz9Ib9kVCYfqNMX6/LfNu+cEafmY6ECP1cV5Vmv+TH2fuasMosKjtbH2fAdDi97sbd29tdEK+g==}
'@kevisual/app@0.0.2':
resolution: {integrity: sha512-DdUkrsLxHO31y5nYl1qAoBPbvTrunztN3z84ow73Of3kZADJRKmjZtrSOMX53vGVgg74AoLOxbYggoWvil9Ifg==}
'@kevisual/cache@0.0.3':
resolution: {integrity: sha512-BWEck69KYL96/ywjYVkML974RHjDJTj2ITQND1zFPR+hlBV1H1p55QZgSYRJCObg3EAV1S9Zic/fR2T4pfe8yg==}
@@ -1292,6 +1295,9 @@ packages:
'@kevisual/query@0.0.32':
resolution: {integrity: sha512-9WN9cjmwSW8I5A0SqITdts9oxlLBGdPP7kJ8vwrxkaQteHS9FzxKuMBJxZzGKZdyte/zJDvdrE+lMf254BGbbg==}
'@kevisual/query@0.0.33':
resolution: {integrity: sha512-3w74bcLpwV3z483eg8n0DgkftfjWC6iLONXBvfyjW6IZf6jMOuouFaM4Rk+uEsTgElU6XGMKseNTp6dlQdWYkg==}
'@kevisual/registry@0.0.1':
resolution: {integrity: sha512-//OHu9m4JDrMjgP8o8dcjZd3D3IAUkRVlkTSviouZEH7r5m7mccA3Hvzw0XJ/lelx6exC6LWsyv6c4uV0Dp+gw==}
@@ -1304,6 +1310,9 @@ packages:
'@kevisual/router@0.0.39':
resolution: {integrity: sha512-jE7/csRkMUuuSWl5RZHbOY44xL/2RI/vAJzCsqt150taW5CAri3efdaQJOQlzghlOqqA+1ZyGajxUAYv/HaQxA==}
'@kevisual/router@0.0.48':
resolution: {integrity: sha512-WsSvT+NpfC/bZbaAzE3WSKD2DRZP0JuPQJGr4YucSdO/lOLB4cEpOZRbPlV3l7G064ow8QJRAN2DUW+bRjrp1A==}
'@kevisual/types@0.0.10':
resolution: {integrity: sha512-Q73uzzjk9UidumnmCvOpgzqDDvQxsblz22bIFuoiioUFJWwaparx8bpd8ArRyFojicYL1YJoFDzDZ9j9NN8grA==}
@@ -2064,8 +2073,8 @@ packages:
'@types/braces@3.0.5':
resolution: {integrity: sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==}
'@types/bun@1.3.4':
resolution: {integrity: sha512-EEPTKXHP+zKGPkhRLv+HI0UEX8/o+65hqARxLy8Ov5rIxMBPNTjeZww00CIihrIQGEQBYg+0roO5qOnS/7boGA==}
'@types/bun@1.3.5':
resolution: {integrity: sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w==}
'@types/crypto-js@4.2.2':
resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
@@ -2213,15 +2222,27 @@ packages:
'@vue/compiler-core@3.5.25':
resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==}
'@vue/compiler-core@3.5.26':
resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==}
'@vue/compiler-dom@3.5.25':
resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==}
'@vue/compiler-dom@3.5.26':
resolution: {integrity: sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==}
'@vue/compiler-sfc@3.5.25':
resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==}
'@vue/compiler-sfc@3.5.26':
resolution: {integrity: sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==}
'@vue/compiler-ssr@3.5.25':
resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==}
'@vue/compiler-ssr@3.5.26':
resolution: {integrity: sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==}
'@vue/devtools-core@7.7.9':
resolution: {integrity: sha512-48jrBSwG4GVQRvVeeXn9p9+dlx+ISgasM7SxZZKczseohB0cBz+ITKr4YbLWjmJdy45UHL7UMPlR4Y0CWTRcSQ==}
peerDependencies:
@@ -2233,23 +2254,26 @@ packages:
'@vue/devtools-shared@7.7.9':
resolution: {integrity: sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==}
'@vue/reactivity@3.5.25':
resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==}
'@vue/reactivity@3.5.26':
resolution: {integrity: sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==}
'@vue/runtime-core@3.5.25':
resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==}
'@vue/runtime-core@3.5.26':
resolution: {integrity: sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==}
'@vue/runtime-dom@3.5.25':
resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==}
'@vue/runtime-dom@3.5.26':
resolution: {integrity: sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==}
'@vue/server-renderer@3.5.25':
resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==}
'@vue/server-renderer@3.5.26':
resolution: {integrity: sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==}
peerDependencies:
vue: 3.5.25
vue: 3.5.26
'@vue/shared@3.5.25':
resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==}
'@vue/shared@3.5.26':
resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==}
abort-controller@3.0.0:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
@@ -2465,8 +2489,8 @@ packages:
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
bun-types@1.3.4:
resolution: {integrity: sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ==}
bun-types@1.3.5:
resolution: {integrity: sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw==}
bundle-name@4.1.0:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
@@ -2885,6 +2909,10 @@ packages:
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
engines: {node: '>=0.12'}
entities@7.0.0:
resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==}
engines: {node: '>=0.12'}
error-stack-parser-es@0.1.5:
resolution: {integrity: sha512-xHku1X40RO+fO8yJ8Wh2f2rZWVjqyhb1zgq1yZ8aZRQkv6OOKhKWRUaht3eSCUbAOBaKIgM+ykwFLE+QUxgGeg==}
@@ -3665,8 +3693,8 @@ packages:
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
lucide-react@0.561.0:
resolution: {integrity: sha512-Y59gMY38tl4/i0qewcqohPdEbieBy7SovpBL9IFebhc2mDd8x4PZSOsiFRkpPcOq6bj1r/mjH/Rk73gSlIJP2A==}
lucide-react@0.562.0:
resolution: {integrity: sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -5063,8 +5091,8 @@ packages:
resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
engines: {node: '>=0.10.0'}
vue@3.5.25:
resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==}
vue@3.5.26:
resolution: {integrity: sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
@@ -5364,15 +5392,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@astrojs/vue@5.1.3(@types/node@25.0.3)(astro@5.16.6(@types/node@25.0.3)(idb-keyval@6.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2))(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(vue@3.5.25(typescript@5.8.2))':
'@astrojs/vue@5.1.3(@types/node@25.0.3)(astro@5.16.6(@types/node@25.0.3)(idb-keyval@6.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2))(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(vue@3.5.26(typescript@5.8.2))':
dependencies:
'@vitejs/plugin-vue': 5.2.1(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.25(typescript@5.8.2))
'@vitejs/plugin-vue-jsx': 4.2.0(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.25(typescript@5.8.2))
'@vitejs/plugin-vue': 5.2.1(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.8.2))
'@vitejs/plugin-vue-jsx': 4.2.0(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.8.2))
'@vue/compiler-sfc': 3.5.25
astro: 5.16.6(@types/node@25.0.3)(idb-keyval@6.2.1)(jiti@2.6.1)(lightningcss@1.30.2)(rollup@4.43.0)(typescript@5.8.2)
vite: 6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
vite-plugin-vue-devtools: 7.7.9(rollup@4.43.0)(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.25(typescript@5.8.2))
vue: 3.5.25(typescript@5.8.2)
vite-plugin-vue-devtools: 7.7.9(rollup@4.43.0)(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.8.2))
vue: 3.5.26(typescript@5.8.2)
transitivePeerDependencies:
- '@nuxt/kit'
- '@types/node'
@@ -6281,6 +6309,19 @@ snapshots:
- dotenv
- supports-color
'@kevisual/app@0.0.2(dotenv@17.2.3)':
dependencies:
'@kevisual/ai': 0.0.19
'@kevisual/context': 0.0.4
'@kevisual/query': 0.0.32
'@kevisual/router': 0.0.39
'@kevisual/use-config': 1.0.21(dotenv@17.2.3)
mitt: 3.0.1
nanoid: 5.1.6
transitivePeerDependencies:
- dotenv
- supports-color
'@kevisual/cache@0.0.3':
dependencies:
idb-keyval: 6.2.1
@@ -6362,10 +6403,10 @@ snapshots:
'@kevisual/permission@0.0.3': {}
'@kevisual/query-login@0.0.7(@kevisual/query@0.0.32)':
'@kevisual/query-login@0.0.7(@kevisual/query@0.0.33)':
dependencies:
'@kevisual/cache': 0.0.3
'@kevisual/query': 0.0.32
'@kevisual/query': 0.0.33
dotenv: 17.2.3
'@kevisual/query@0.0.30': {}
@@ -6374,6 +6415,8 @@ snapshots:
'@kevisual/query@0.0.32': {}
'@kevisual/query@0.0.33': {}
'@kevisual/registry@0.0.1(typescript@5.8.2)':
dependencies:
class-variance-authority: 0.7.1
@@ -6408,7 +6451,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@kevisual/router@0.0.39(supports-color@10.2.2)':
'@kevisual/router@0.0.39':
dependencies:
path-to-regexp: 8.3.0
selfsigned: 5.2.0
send: 1.2.1(supports-color@10.2.2)
transitivePeerDependencies:
- supports-color
'@kevisual/router@0.0.48(supports-color@10.2.2)':
dependencies:
path-to-regexp: 8.3.0
selfsigned: 5.2.0
@@ -7338,9 +7389,9 @@ snapshots:
'@types/braces@3.0.5': {}
'@types/bun@1.3.4':
'@types/bun@1.3.5':
dependencies:
bun-types: 1.3.4
bun-types: 1.3.5
'@types/crypto-js@4.2.2': {}
@@ -7482,21 +7533,21 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@vitejs/plugin-vue-jsx@4.2.0(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.25(typescript@5.8.2))':
'@vitejs/plugin-vue-jsx@4.2.0(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.8.2))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5)
'@rolldown/pluginutils': 1.0.0-beta.55
'@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.5)
vite: 6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
vue: 3.5.25(typescript@5.8.2)
vue: 3.5.26(typescript@5.8.2)
transitivePeerDependencies:
- supports-color
'@vitejs/plugin-vue@5.2.1(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.25(typescript@5.8.2))':
'@vitejs/plugin-vue@5.2.1(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.8.2))':
dependencies:
vite: 6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)
vue: 3.5.25(typescript@5.8.2)
vue: 3.5.26(typescript@5.8.2)
'@vue/babel-helper-vue-transform-on@1.5.0': {}
@@ -7535,11 +7586,24 @@ snapshots:
estree-walker: 2.0.2
source-map-js: 1.2.1
'@vue/compiler-core@3.5.26':
dependencies:
'@babel/parser': 7.28.5
'@vue/shared': 3.5.26
entities: 7.0.0
estree-walker: 2.0.2
source-map-js: 1.2.1
'@vue/compiler-dom@3.5.25':
dependencies:
'@vue/compiler-core': 3.5.25
'@vue/shared': 3.5.25
'@vue/compiler-dom@3.5.26':
dependencies:
'@vue/compiler-core': 3.5.26
'@vue/shared': 3.5.26
'@vue/compiler-sfc@3.5.25':
dependencies:
'@babel/parser': 7.28.5
@@ -7552,12 +7616,29 @@ snapshots:
postcss: 8.5.6
source-map-js: 1.2.1
'@vue/compiler-sfc@3.5.26':
dependencies:
'@babel/parser': 7.28.5
'@vue/compiler-core': 3.5.26
'@vue/compiler-dom': 3.5.26
'@vue/compiler-ssr': 3.5.26
'@vue/shared': 3.5.26
estree-walker: 2.0.2
magic-string: 0.30.21
postcss: 8.5.6
source-map-js: 1.2.1
'@vue/compiler-ssr@3.5.25':
dependencies:
'@vue/compiler-dom': 3.5.25
'@vue/shared': 3.5.25
'@vue/devtools-core@7.7.9(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.25(typescript@5.8.2))':
'@vue/compiler-ssr@3.5.26':
dependencies:
'@vue/compiler-dom': 3.5.26
'@vue/shared': 3.5.26
'@vue/devtools-core@7.7.9(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.8.2))':
dependencies:
'@vue/devtools-kit': 7.7.9
'@vue/devtools-shared': 7.7.9
@@ -7565,7 +7646,7 @@ snapshots:
nanoid: 5.1.6
pathe: 2.0.3
vite-hot-client: 2.1.0(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))
vue: 3.5.25(typescript@5.8.2)
vue: 3.5.26(typescript@5.8.2)
transitivePeerDependencies:
- vite
@@ -7583,30 +7664,32 @@ snapshots:
dependencies:
rfdc: 1.4.1
'@vue/reactivity@3.5.25':
'@vue/reactivity@3.5.26':
dependencies:
'@vue/shared': 3.5.25
'@vue/shared': 3.5.26
'@vue/runtime-core@3.5.25':
'@vue/runtime-core@3.5.26':
dependencies:
'@vue/reactivity': 3.5.25
'@vue/shared': 3.5.25
'@vue/reactivity': 3.5.26
'@vue/shared': 3.5.26
'@vue/runtime-dom@3.5.25':
'@vue/runtime-dom@3.5.26':
dependencies:
'@vue/reactivity': 3.5.25
'@vue/runtime-core': 3.5.25
'@vue/shared': 3.5.25
csstype: 3.1.3
'@vue/reactivity': 3.5.26
'@vue/runtime-core': 3.5.26
'@vue/shared': 3.5.26
csstype: 3.2.3
'@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.8.2))':
'@vue/server-renderer@3.5.26(vue@3.5.26(typescript@5.8.2))':
dependencies:
'@vue/compiler-ssr': 3.5.25
'@vue/shared': 3.5.25
vue: 3.5.25(typescript@5.8.2)
'@vue/compiler-ssr': 3.5.26
'@vue/shared': 3.5.26
vue: 3.5.26(typescript@5.8.2)
'@vue/shared@3.5.25': {}
'@vue/shared@3.5.26': {}
abort-controller@3.0.0:
dependencies:
event-target-shim: 5.0.1
@@ -7945,7 +8028,7 @@ snapshots:
base64-js: 1.5.1
ieee754: 1.2.1
bun-types@1.3.4:
bun-types@1.3.5:
dependencies:
'@types/node': 25.0.3
@@ -8313,6 +8396,8 @@ snapshots:
entities@6.0.1: {}
entities@7.0.0: {}
error-stack-parser-es@0.1.5: {}
es-define-property@1.0.1: {}
@@ -9239,7 +9324,7 @@ snapshots:
dependencies:
react: 19.2.3
lucide-react@0.561.0(react@19.2.3):
lucide-react@0.562.0(react@19.2.3):
dependencies:
react: 19.2.3
@@ -11025,9 +11110,9 @@ snapshots:
- rollup
- supports-color
vite-plugin-vue-devtools@7.7.9(rollup@4.43.0)(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.25(typescript@5.8.2)):
vite-plugin-vue-devtools@7.7.9(rollup@4.43.0)(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.8.2)):
dependencies:
'@vue/devtools-core': 7.7.9(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.25(typescript@5.8.2))
'@vue/devtools-core': 7.7.9(vite@6.4.1(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vue@3.5.26(typescript@5.8.2))
'@vue/devtools-kit': 7.7.9
'@vue/devtools-shared': 7.7.9
execa: 9.6.1
@@ -11083,13 +11168,13 @@ snapshots:
void-elements@3.1.0: {}
vue@3.5.25(typescript@5.8.2):
vue@3.5.26(typescript@5.8.2):
dependencies:
'@vue/compiler-dom': 3.5.25
'@vue/compiler-sfc': 3.5.25
'@vue/runtime-dom': 3.5.25
'@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.8.2))
'@vue/shared': 3.5.25
'@vue/compiler-dom': 3.5.26
'@vue/compiler-sfc': 3.5.26
'@vue/runtime-dom': 3.5.26
'@vue/server-renderer': 3.5.26(vue@3.5.26(typescript@5.8.2))
'@vue/shared': 3.5.26
optionalDependencies:
typescript: 5.8.2

View File

@@ -1,4 +1,4 @@
import { App } from '@kevisual/app/src/app.ts';
import { App } from '@kevisual/app/mod.ts';
import { storage } from '../module/query.ts';
export const app = new App({ token: storage.getItem('token') || '', storage });
import { sessionStorage } from '../module/cache.ts';
export const app = new App({ token: storage.getItem('token') || '', storage: sessionStorage });

21
src/module/cache.ts Normal file
View File

@@ -0,0 +1,21 @@
import { LRUCache } from 'lru-cache'
export const cache = new LRUCache<string, any>({
max: 10000, // 最大缓存数量
ttl: 1000 * 60 * 60 * 24 * 7, // 缓存过期时间单位为毫秒这里设置为7天
});
export const sessionStorage = {
setItem: (key: string, value: any) => {
cache.set(key, value);
},
getItem: (key: string) => {
return cache.get(key);
},
removeItem: (key: string) => {
cache.delete(key);
},
clear: () => {
cache.clear();
}
}