fix: 更新依赖项版本并优化远程应用连接逻辑

This commit is contained in:
2026-02-21 06:28:20 +08:00
parent 68c1976754
commit 13b0f45d3e
13 changed files with 184 additions and 76 deletions

View File

@@ -44,7 +44,7 @@
"devDependencies": { "devDependencies": {
"@inquirer/prompts": "^8.2.1", "@inquirer/prompts": "^8.2.1",
"@kevisual/ai": "^0.0.24", "@kevisual/ai": "^0.0.24",
"@kevisual/api": "^0.0.55", "@kevisual/api": "^0.0.57",
"@kevisual/load": "^0.0.6", "@kevisual/load": "^0.0.6",
"@kevisual/local-app-manager": "^0.1.32", "@kevisual/local-app-manager": "^0.1.32",
"@kevisual/logger": "^0.0.4", "@kevisual/logger": "^0.0.4",
@@ -76,7 +76,7 @@
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.994.0", "@aws-sdk/client-s3": "^3.995.0",
"@kevisual/js-filter": "^0.0.5", "@kevisual/js-filter": "^0.0.5",
"@kevisual/oss": "^0.0.19", "@kevisual/oss": "^0.0.19",
"@kevisual/video-tools": "^0.0.13", "@kevisual/video-tools": "^0.0.13",

View File

@@ -91,7 +91,6 @@ export type AssistantConfigData = {
*/ */
url?: string; url?: string;
} }
token?: string;
registry?: string; // https://kevisual.cn registry?: string; // https://kevisual.cn
/** /**
* 前端代理,比如/root/home 转到https://kevisual.cn/root/home * 前端代理,比如/root/home 转到https://kevisual.cn/root/home

View File

@@ -7,12 +7,13 @@ import glob from 'fast-glob';
import type { App } from '@kevisual/router'; import type { App } from '@kevisual/router';
import { RemoteApp } from '@/module/remote-app/remote-app.ts'; import { RemoteApp } from '@/module/remote-app/remote-app.ts';
import { logger } from '@/module/logger.ts'; import { logger } from '@/module/logger.ts';
import { getEnvToken } from '@/module/http-token.ts';
import { initApi } from '@kevisual/api/proxy' import { initApi } from '@kevisual/api/proxy'
import { Query } from '@kevisual/query'; import { Query } from '@kevisual/query';
import { initLightCode } from '@/module/light-code/index.ts'; import { initLightCode } from '@/module/light-code/index.ts';
import { ModuleResolver } from './assistant-app-resolve.ts'; import { ModuleResolver } from './assistant-app-resolve.ts';
import z from 'zod'; import z from 'zod';
import { assistantQuery } from '@/app.ts';
import { useKey } from '@kevisual/context';
export class AssistantApp extends Manager { export class AssistantApp extends Manager {
config: AssistantConfig; config: AssistantConfig;
pagesPath: string; pagesPath: string;
@@ -23,8 +24,8 @@ export class AssistantApp extends Manager {
constructor(config: AssistantConfig, mainApp?: App) { constructor(config: AssistantConfig, mainApp?: App) {
config.checkMounted(); config.checkMounted();
const appsPath = config?.configPath?.appsDir || path.join(process.cwd(), 'apps'); const appsPath = config?.configPath?.appsDir
const pagesPath = config?.configPath?.pagesDir || path.join(process.cwd(), 'pages'); const pagesPath = config?.configPath?.pagesDir;
const appsConfigPath = config.configPath?.appsConfigPath; const appsConfigPath = config.configPath?.appsConfigPath;
const configFimename = path.basename(appsConfigPath || ''); const configFimename = path.basename(appsConfigPath || '');
super({ super({
@@ -80,6 +81,12 @@ export class AssistantApp extends Manager {
return pagesParse; return pagesParse;
} }
/**
* 初始化远程应用连接,如果配置了远程应用且启用,则尝试连接远程应用服务器,并设置自动重连机制.
* 应用暴露
* @info 需要登录权限
* @param opts
*/
async initRemoteApp(opts?: { token?: string, enabled?: boolean }) { async initRemoteApp(opts?: { token?: string, enabled?: boolean }) {
const config = this.config.getConfig(); const config = this.config.getConfig();
const share = config?.share; const share = config?.share;
@@ -90,8 +97,17 @@ export class AssistantApp extends Manager {
this.remoteApp = null; this.remoteApp = null;
this.remoteIsConnected = false; this.remoteIsConnected = false;
} }
const token = config?.token || opts?.token || getEnvToken() as string; let token = opts?.token;
const url = new URL(share.url || 'https://kevisual.cn/ws/proxy'); if (!token) {
token = await assistantQuery.queryLogin.getToken();
}
let shareUrl = share?.url;
if (!shareUrl) {
const _url = new URL(config?.registry || 'https://kevisual.cn/');
_url.pathname = '/ws/proxy';
shareUrl = _url.toString();
}
const url = new URL(shareUrl);
const id = config?.app?.id; const id = config?.app?.id;
if (token && url && id) { if (token && url && id) {
const remoteApp = new RemoteApp({ const remoteApp = new RemoteApp({
@@ -129,11 +145,22 @@ export class AssistantApp extends Manager {
this.remoteApp = remoteApp; this.remoteApp = remoteApp;
} else { } else {
if (!token) { if (!token) {
logger.error('Token是远程应用连接必须的参数'); logger.error('[remote-app] cli当前未登录无法连接远程app');
} else if (!id) {
logger.error('[remote-app] app id不存在无法连接远程app');
} }
} }
} }
} }
/**
* 本地路由初始化,根据配置加载应用的模块。
* 加载局域网或者某一个链接的远程路由, 或者代码仓库的动态加载的light-code模块实时同步远程文件执行
* @info 不需要登录
* 配置项说明:
* - router.proxy: 数组,包含需要代理的路由信息,每项可以是以下两种类型:
* - lightcode: 轻代码模块配置
* @returns
*/
async initRouterApp() { async initRouterApp() {
const config = this.config.getConfig(); const config = this.config.getConfig();
const routerProxy = config?.router?.proxy || []; const routerProxy = config?.router?.proxy || [];
@@ -209,6 +236,10 @@ export class AssistantApp extends Manager {
} }
} }
} }
/**
* 动态加载文件插件模块的应用模块
* @info 不需要登录
*/
async initRoutes() { async initRoutes() {
const routes = this.config.getConfig().routes || []; const routes = this.config.getConfig().routes || [];
for (const route of routes) { for (const route of routes) {
@@ -222,4 +253,53 @@ export class AssistantApp extends Manager {
} }
} }
} }
/**
* 检查本地用户登录状态,如果未登录且存在 CNB_TOKEN则尝试使用 CNB_TOKEN 登录并更新用户信息
*/
async checkLocalUser() {
const config = this.config.getConfig();
const auth = config?.auth;
let checkCNB = false;
if (!auth?.username) {
checkCNB = true;
} else {
let temp = await assistantQuery.queryLogin.getToken()
if (temp) {
const isExpired = await assistantQuery.queryLogin.checkTokenValid()
console.log('Token 是否过期', isExpired);
}
logger.info('[assistant] 当前登录用户', auth.username, 'token有效性检查结果', !!temp);
}
const cnbToken = useKey('CNB_TOKEN');
if (!checkCNB && cnbToken) {
const res = await assistantQuery.query.post({
path: 'user',
key: 'cnb-login',
payload: {
data: {
cnbToken: cnbToken,
}
}
});
if (res.code === 200) {
logger.info('CNB登录成功用户信息已更新');
const resUser = await assistantQuery.queryLogin.beforeSetLoginUser(res.data)
if (resUser.code === 200) {
const userInfo = resUser.data;
auth.username = userInfo.username;
auth.share = 'protected'
const app = config?.app || {};
if (!app?.id) {
app.id = 'dev-cnb'
}
this.config.setConfig({
auth,
app
});
} else {
console.error('CNB登录失败无法获取用户信息', resUser);
}
}
}
}
} }

View File

@@ -1,5 +1,4 @@
import { useKey } from '@kevisual/use-config'; import { IncomingMessage } from 'node:http';
import http from 'node:http';
export const error = (msg: string, code = 500) => { export const error = (msg: string, code = 500) => {
return JSON.stringify({ code, message: msg }); return JSON.stringify({ code, message: msg });
}; };
@@ -16,7 +15,12 @@ const cookie = {
return cookies; return cookies;
} }
} }
export const getToken = async (req: http.IncomingMessage) => { /**
* 从请求中获取token优先级Authorization header > query parameter > cookie
* @param req
* @returns
*/
export const getToken = async (req: IncomingMessage) => {
let token = (req.headers?.['authorization'] as string) || (req.headers?.['Authorization'] as string) || ''; let token = (req.headers?.['authorization'] as string) || (req.headers?.['Authorization'] as string) || '';
const url = new URL(req.url || '', 'http://localhost'); const url = new URL(req.url || '', 'http://localhost');
if (!token) { if (!token) {
@@ -32,8 +36,3 @@ export const getToken = async (req: http.IncomingMessage) => {
return { token }; return { token };
}; };
export const getEnvToken = () => {
const envTokne = useKey('KEVISUAL_TOKEN') || '';
return envTokne;
}

View File

@@ -8,6 +8,7 @@ const codeDemoId = '0e700dc8-90dd-41b7-91dd-336ea51de3d2'
import { filter } from "@kevisual/js-filter"; import { filter } from "@kevisual/js-filter";
import { getHash, getStringHash } from '../file-hash.ts'; import { getHash, getStringHash } from '../file-hash.ts';
import { AssistantConfig } from '@/lib.ts'; import { AssistantConfig } from '@/lib.ts';
import { assistantQuery } from '@/app.ts';
const codeDemo = `// 这是一个示例代码文件 const codeDemo = `// 这是一个示例代码文件
import {App} from '@kevisual/router'; import {App} from '@kevisual/router';
@@ -48,11 +49,11 @@ export const initLightCode = async (opts: Opts) => {
console.log('初始化 light-code 路由'); console.log('初始化 light-code 路由');
const config = opts.config as AssistantInit; const config = opts.config as AssistantInit;
const app = opts.router; const app = opts.router;
const token = config.getConfig()?.token || ''; const token = await assistantQuery.getToken();
const query = config.query; const query = config.query;
const sync = opts.sync ?? 'remote'; const sync = opts.sync ?? 'remote';
if (!config || !app) { if (!config || !app) {
console.error('initLightCode 缺少必要参数, config 或 app'); console.error('[light-code] initLightCode 缺少必要参数, config 或 app');
return; return;
} }
const lightcodeDir = opts.rootPath; const lightcodeDir = opts.rootPath;
@@ -126,7 +127,7 @@ export const initLightCode = async (opts: Opts) => {
} }
diffList = findGlob({ cwd: lightcodeDir }); diffList = findGlob({ cwd: lightcodeDir });
} else { } else {
console.error('light-code 同步失败', queryRes.message); console.error('[light-code] 同步失败', queryRes.message);
diffList = codeFiles; diffList = codeFiles;
} }
} else if (sync === 'local') { } else if (sync === 'local') {
@@ -191,22 +192,22 @@ export const initLightCode = async (opts: Opts) => {
} }
} }
} else { } else {
console.error('light-code 路由执行失败', runRes.error); console.error('[light-code] 路由执行失败', runRes.error);
} }
} }
console.log(`light-code 路由注册成功`, `注册${diffList.length}个路由`); console.log(`[light-code] 路由注册成功`, `注册${diffList.length}个路由`);
} }
export const clearLightCodeRoutes = (opts: Pick<Opts, 'router'>) => { export const clearLightCodeRoutes = (opts: Pick<Opts, 'router'>) => {
const app = opts.router; const app = opts.router;
if (!app) { if (!app) {
console.error('clearLightCodeRoutes 缺少必要参数, app'); console.error('[light-code] clearLightCodeRoutes 缺少必要参数, app');
return; return;
} }
const routes = app.getList(); const routes = app.getList();
for (const route of routes) { for (const route of routes) {
if (route.metadata?.source === 'light-code') { if (route.metadata?.source === 'light-code') {
// console.log(`删除 light-code 路由: ${route.path} ${route.id}`); // console.log(`[light-code] 删除 light-code 路由: ${route.path} ${route.id}`);
app.removeById(route.id); app.removeById(route.id);
} }
} }

View File

@@ -41,14 +41,14 @@ app.route({
} }
return; return;
} }
await manager.initRemoteApp({ enabled: true, token: ctx.query?.token }).then(() => { try {
const res = await manager.initRemoteApp({ enabled: true, token: ctx.query?.token })
ctx.body = { ctx.body = {
content: '远程app连接成功', content: '远程app连接成功',
} }
}).catch((err) => { } catch (error) {
ctx.body = { ctx.body = {
content: `远程app连接失败: ${err.message}`, content: '远程app连接失败',
} }
}); }
}).addTo(app); }).addTo(app);

View File

@@ -1,4 +1,5 @@
import { app, assistantConfig } from '../../app.ts'; import { app, assistantConfig } from '../../app.ts';
import { forwardCookie } from './utils/cookie.ts';
app.route({ app.route({
path: 'admin', path: 'admin',
@@ -23,19 +24,7 @@ app.route({
password, password,
}), }),
}); });
forwardCookie(ctx, res);
// 转发上游服务器返回的所有 set-cookie支持多个 cookie
const setCookieHeaders = res.headers.getSetCookie?.() || [];
if (setCookieHeaders.length > 0) {
// 设置多个 cookie 到原生 http.ServerResponse
ctx.res.setHeader('Set-Cookie', setCookieHeaders);
} else {
// 兼容旧版本,使用 get 方法
const setCookieHeader = res.headers.get('set-cookie');
if (setCookieHeader) {
ctx.res.setHeader('Set-Cookie', setCookieHeader);
}
}
const responseData = await res.json(); const responseData = await res.json();
console.debug('admin login response', { res: responseData }); console.debug('admin login response', { res: responseData });
@@ -73,6 +62,9 @@ app.route({
key: 'me' key: 'me'
}).define(async (ctx) => { }).define(async (ctx) => {
const token = ctx.query.token; const token = ctx.query.token;
if (!token) {
ctx.throw(401, 'token is required');
}
const res = await assistantConfig.query.post({ const res = await assistantConfig.query.post({
path: 'user', path: 'user',
key: 'me', key: 'me',

View File

@@ -0,0 +1,14 @@
export const forwardCookie = (ctx: any, res: any) => {
// 转发上游服务器返回的所有 set-cookie支持多个 cookie
const setCookieHeaders = res.headers.getSetCookie?.() || [];
if (setCookieHeaders.length > 0) {
// 设置多个 cookie 到原生 http.ServerResponse
ctx.res.setHeader('Set-Cookie', setCookieHeaders);
} else {
// 兼容旧版本,使用 get 方法
const setCookieHeader = res.headers.get('set-cookie');
if (setCookieHeader) {
ctx.res.setHeader('Set-Cookie', setCookieHeader);
}
}
}

View File

@@ -47,14 +47,14 @@ export const runServer = async (port: number = 51515, listenPath = '127.0.0.1')
qwenAsr, qwenAsr,
]); ]);
const manager = useContextKey('manager', new AssistantApp(assistantConfig, app)); const manager = useContextKey('manager', new AssistantApp(assistantConfig, app));
setTimeout(() => { setTimeout(async () => {
manager.load({ runtime: 'client' }).then(() => { await manager.load({ runtime: 'client' });
console.log('Assistant App Loaded'); console.log('Assistant App Loaded');
}); await manager.checkLocalUser()
manager.initRemoteApp() await manager.initRemoteApp();
manager.initRouterApp() await manager.initRouterApp();
if (runtime.isServer) { if (runtime.isServer) {
manager.initRoutes(); await manager.initRoutes();
} }
}, 1000); }, 1000);

View File

@@ -45,7 +45,7 @@ const authFilter = async (req: http.IncomingMessage, res: http.ServerResponse) =
return { code: 200, message: '允许访问根路径' }; return { code: 200, message: '允许访问根路径' };
} }
// 放开首页 // 放开首页
if (pathname.startsWith('/root/home') || pathname === '/root/cli/docs/') { if (pathname.startsWith('/root/home') || pathname === '/root/cli-center/') {
return { code: 200, message: '允许访问首页' }; return { code: 200, message: '允许访问首页' };
} }
// 放开api 以 /api /v1, /client, /serve 开头的请求 // 放开api 以 /api /v1, /client, /serve 开头的请求
@@ -86,7 +86,7 @@ export const proxyRoute = async (req: http.IncomingMessage, res: http.ServerResp
let noAdmin = !auth.username; let noAdmin = !auth.username;
const toSetting = () => { const toSetting = () => {
res.writeHead(302, { Location: `/root/cli/setting/` }); res.writeHead(302, { Location: `/root/cli-center/` });
res.end(); res.end();
return true; return true;
} }

View File

@@ -6,7 +6,7 @@ const main = async () => {
const config = assistantConfig?.getConfig(); const config = assistantConfig?.getConfig();
const share = config?.share; const share = config?.share;
if (share && share.enabled !== false) { if (share && share.enabled !== false) {
const token = config?.token; const token = ''
const url = new URL(share.url || 'https://kevisual.cn/ws/proxy'); const url = new URL(share.url || 'https://kevisual.cn/ws/proxy');
const id = config?.app?.id; const id = config?.app?.id;
if (!id) { if (!id) {
@@ -14,7 +14,6 @@ const main = async () => {
return; return;
} }
if (!token) { if (!token) {
console.error('Token is required for remote app connection.');
return; return;
} }
const remoteApp = new RemoteApp({ const remoteApp = new RemoteApp({

66
pnpm-lock.yaml generated
View File

@@ -127,8 +127,8 @@ importers:
assistant: assistant:
dependencies: dependencies:
'@aws-sdk/client-s3': '@aws-sdk/client-s3':
specifier: ^3.994.0 specifier: ^3.995.0
version: 3.994.0 version: 3.995.0
'@kevisual/js-filter': '@kevisual/js-filter':
specifier: ^0.0.5 specifier: ^0.0.5
version: 0.0.5 version: 0.0.5
@@ -170,8 +170,8 @@ importers:
specifier: ^0.0.24 specifier: ^0.0.24
version: 0.0.24 version: 0.0.24
'@kevisual/api': '@kevisual/api':
specifier: ^0.0.55 specifier: ^0.0.57
version: 0.0.55(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) version: 0.0.57(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@kevisual/load': '@kevisual/load':
specifier: ^0.0.6 specifier: ^0.0.6
version: 0.0.6 version: 0.0.6
@@ -459,8 +459,8 @@ packages:
'@aws-crypto/util@5.2.0': '@aws-crypto/util@5.2.0':
resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==}
'@aws-sdk/client-s3@3.994.0': '@aws-sdk/client-s3@3.995.0':
resolution: {integrity: sha512-zIVQt/XfE2zTFrcPEf8R+KRaRD1++XHMPRhxXM2kVA6NA6Aq/cFCUyYOYYwSbWLF/XeToaX1auYGn3IoZKruPQ==} resolution: {integrity: sha512-r+t8qrQ0m9zoovYOH+wilp/glFRB/E+blsDyWzq2C+9qmyhCAQwaxjLaHM8T/uluAmhtZQIYqOH9ILRnvWtRNw==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
'@aws-sdk/client-sso@3.993.0': '@aws-sdk/client-sso@3.993.0':
@@ -555,8 +555,8 @@ packages:
resolution: {integrity: sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==} resolution: {integrity: sha512-v4J8qYAWfOMcZ4MJUyatntOicTzEMaU7j3OpkRCGGFSL2NgXQ5VbxauIyORA+pxdKZ0qQG2tCQjQjZDlXEC3Ow==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
'@aws-sdk/signature-v4-multi-region@3.994.0': '@aws-sdk/signature-v4-multi-region@3.995.0':
resolution: {integrity: sha512-8y04Lv497KKd7f2TVlm2RaKQaNfnY17ZH8d3m+7sW/3R3BhZvHgWQZyqTb/vcN2ERz1YAnWx6woJyB3ZNFvakw==} resolution: {integrity: sha512-9Qx5JcAucnxnomREPb2D6L8K8GLG0rknt3+VK/BU3qTUynAcV4W21DQ04Z2RKDw+DYpW88lsZpXbVetWST2WUg==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
'@aws-sdk/token-providers@3.993.0': '@aws-sdk/token-providers@3.993.0':
@@ -575,8 +575,8 @@ packages:
resolution: {integrity: sha512-j6vioBeRZ4eHX4SWGvGPpwGg/xSOcK7f1GL0VM+rdf3ZFTIsUEhCFmD78B+5r2PgztcECSzEfvHQX01k8dPQPw==} resolution: {integrity: sha512-j6vioBeRZ4eHX4SWGvGPpwGg/xSOcK7f1GL0VM+rdf3ZFTIsUEhCFmD78B+5r2PgztcECSzEfvHQX01k8dPQPw==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
'@aws-sdk/util-endpoints@3.994.0': '@aws-sdk/util-endpoints@3.995.0':
resolution: {integrity: sha512-L2obUBw4ACMMd1F/SG5LdfPyZ0xJNs9Maifwr3w0uWO+4YvHmk9FfRskfSfE/SLZ9S387oSZ+1xiP7BfVCP/Og==} resolution: {integrity: sha512-aym/pjB8SLbo9w2nmkrDdAAVKVlf7CM71B9mKhjDbJTzwpSFBPHqJIMdDyj0mLumKC0aIVDr1H6U+59m9GvMFw==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
'@aws-sdk/util-locate-window@3.965.2': '@aws-sdk/util-locate-window@3.965.2':
@@ -586,8 +586,8 @@ packages:
'@aws-sdk/util-user-agent-browser@3.972.3': '@aws-sdk/util-user-agent-browser@3.972.3':
resolution: {integrity: sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==} resolution: {integrity: sha512-JurOwkRUcXD/5MTDBcqdyQ9eVedtAsZgw5rBwktsPTN7QtPiS2Ld1jkJepNgYoCufz1Wcut9iup7GJDoIHp8Fw==}
'@aws-sdk/util-user-agent-node@3.972.9': '@aws-sdk/util-user-agent-node@3.972.10':
resolution: {integrity: sha512-JNswdsLdQemxqaSIBL2HRhsHPUBBziAgoi5RQv6/9avmE5g5RSdt1hWr3mHJ7OxqRYf+KeB11ExWbiqfrnoeaA==} resolution: {integrity: sha512-LVXzICPlsheET+sE6tkcS47Q5HkSTrANIlqL1iFxGAY/wRQ236DX/PCAK56qMh9QJoXAfXfoRW0B0Og4R+X7Nw==}
engines: {node: '>=20.0.0'} engines: {node: '>=20.0.0'}
peerDependencies: peerDependencies:
aws-crt: '>=1.0.0' aws-crt: '>=1.0.0'
@@ -1293,6 +1293,9 @@ packages:
'@kevisual/api@0.0.55': '@kevisual/api@0.0.55':
resolution: {integrity: sha512-ylWpX12tzAULuvxJHhvt7N21SmVOiIV2eVbKSdJ51soo9XO2J7rGNrLcczQ1vPdaSHzCq+9RlAUyd0ogleGJCA==} resolution: {integrity: sha512-ylWpX12tzAULuvxJHhvt7N21SmVOiIV2eVbKSdJ51soo9XO2J7rGNrLcczQ1vPdaSHzCq+9RlAUyd0ogleGJCA==}
'@kevisual/api@0.0.57':
resolution: {integrity: sha512-U2nz+ckWZ4XGASC08xJT6WKQajhFQDd1iDb9tU1dHZECsvNvIzpHLG7RHFN1vahG1MdbQtppPmHgVTF2Zw7RWg==}
'@kevisual/app@0.0.1': '@kevisual/app@0.0.1':
resolution: {integrity: sha512-PEx8P3l0iNSqrz9Ib9kVCYfqNMX6/LfNu+cEafmY6ECP1cV5Vmv+TH2fuasMosKjtbH2fAdDi97sbd29tdEK+g==} resolution: {integrity: sha512-PEx8P3l0iNSqrz9Ib9kVCYfqNMX6/LfNu+cEafmY6ECP1cV5Vmv+TH2fuasMosKjtbH2fAdDi97sbd29tdEK+g==}
@@ -5509,7 +5512,7 @@ snapshots:
'@smithy/util-utf8': 2.3.0 '@smithy/util-utf8': 2.3.0
tslib: 2.8.1 tslib: 2.8.1
'@aws-sdk/client-s3@3.994.0': '@aws-sdk/client-s3@3.995.0':
dependencies: dependencies:
'@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha1-browser': 5.2.0
'@aws-crypto/sha256-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0
@@ -5527,11 +5530,11 @@ snapshots:
'@aws-sdk/middleware-ssec': 3.972.3 '@aws-sdk/middleware-ssec': 3.972.3
'@aws-sdk/middleware-user-agent': 3.972.11 '@aws-sdk/middleware-user-agent': 3.972.11
'@aws-sdk/region-config-resolver': 3.972.3 '@aws-sdk/region-config-resolver': 3.972.3
'@aws-sdk/signature-v4-multi-region': 3.994.0 '@aws-sdk/signature-v4-multi-region': 3.995.0
'@aws-sdk/types': 3.973.1 '@aws-sdk/types': 3.973.1
'@aws-sdk/util-endpoints': 3.994.0 '@aws-sdk/util-endpoints': 3.995.0
'@aws-sdk/util-user-agent-browser': 3.972.3 '@aws-sdk/util-user-agent-browser': 3.972.3
'@aws-sdk/util-user-agent-node': 3.972.9 '@aws-sdk/util-user-agent-node': 3.972.10
'@smithy/config-resolver': 4.4.6 '@smithy/config-resolver': 4.4.6
'@smithy/core': 3.23.2 '@smithy/core': 3.23.2
'@smithy/eventstream-serde-browser': 4.2.8 '@smithy/eventstream-serde-browser': 4.2.8
@@ -5582,7 +5585,7 @@ snapshots:
'@aws-sdk/types': 3.973.1 '@aws-sdk/types': 3.973.1
'@aws-sdk/util-endpoints': 3.993.0 '@aws-sdk/util-endpoints': 3.993.0
'@aws-sdk/util-user-agent-browser': 3.972.3 '@aws-sdk/util-user-agent-browser': 3.972.3
'@aws-sdk/util-user-agent-node': 3.972.9 '@aws-sdk/util-user-agent-node': 3.972.10
'@smithy/config-resolver': 4.4.6 '@smithy/config-resolver': 4.4.6
'@smithy/core': 3.23.2 '@smithy/core': 3.23.2
'@smithy/fetch-http-handler': 5.3.9 '@smithy/fetch-http-handler': 5.3.9
@@ -5844,7 +5847,7 @@ snapshots:
'@aws-sdk/types': 3.973.1 '@aws-sdk/types': 3.973.1
'@aws-sdk/util-endpoints': 3.993.0 '@aws-sdk/util-endpoints': 3.993.0
'@aws-sdk/util-user-agent-browser': 3.972.3 '@aws-sdk/util-user-agent-browser': 3.972.3
'@aws-sdk/util-user-agent-node': 3.972.9 '@aws-sdk/util-user-agent-node': 3.972.10
'@smithy/config-resolver': 4.4.6 '@smithy/config-resolver': 4.4.6
'@smithy/core': 3.23.2 '@smithy/core': 3.23.2
'@smithy/fetch-http-handler': 5.3.9 '@smithy/fetch-http-handler': 5.3.9
@@ -5882,7 +5885,7 @@ snapshots:
'@smithy/types': 4.12.0 '@smithy/types': 4.12.0
tslib: 2.8.1 tslib: 2.8.1
'@aws-sdk/signature-v4-multi-region@3.994.0': '@aws-sdk/signature-v4-multi-region@3.995.0':
dependencies: dependencies:
'@aws-sdk/middleware-sdk-s3': 3.972.11 '@aws-sdk/middleware-sdk-s3': 3.972.11
'@aws-sdk/types': 3.973.1 '@aws-sdk/types': 3.973.1
@@ -5920,7 +5923,7 @@ snapshots:
'@smithy/util-endpoints': 3.2.8 '@smithy/util-endpoints': 3.2.8
tslib: 2.8.1 tslib: 2.8.1
'@aws-sdk/util-endpoints@3.994.0': '@aws-sdk/util-endpoints@3.995.0':
dependencies: dependencies:
'@aws-sdk/types': 3.973.1 '@aws-sdk/types': 3.973.1
'@smithy/types': 4.12.0 '@smithy/types': 4.12.0
@@ -5939,7 +5942,7 @@ snapshots:
bowser: 2.13.1 bowser: 2.13.1
tslib: 2.8.1 tslib: 2.8.1
'@aws-sdk/util-user-agent-node@3.972.9': '@aws-sdk/util-user-agent-node@3.972.10':
dependencies: dependencies:
'@aws-sdk/middleware-user-agent': 3.972.11 '@aws-sdk/middleware-user-agent': 3.972.11
'@aws-sdk/types': 3.973.1 '@aws-sdk/types': 3.973.1
@@ -6630,6 +6633,27 @@ snapshots:
- react-dom - react-dom
- use-sync-external-store - use-sync-external-store
'@kevisual/api@0.0.57(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies:
'@kevisual/context': 0.0.8
'@kevisual/js-filter': 0.0.5
'@kevisual/load': 0.0.6
'@paralleldrive/cuid2': 3.3.0
es-toolkit: 1.44.0
eventemitter3: 5.0.4
fuse.js: 7.1.0
nanoid: 5.1.6
path-browserify-esm: 1.0.6
sonner: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
spark-md5: 3.0.2
zustand: 5.0.11(@types/react@19.2.10)(react@19.2.4)
transitivePeerDependencies:
- '@types/react'
- immer
- react
- react-dom
- use-sync-external-store
'@kevisual/app@0.0.1(dotenv@17.2.3)': '@kevisual/app@0.0.1(dotenv@17.2.3)':
dependencies: dependencies:
'@kevisual/ai': 0.0.19 '@kevisual/ai': 0.0.19