fix: 更新 @kevisual/api 依赖至 0.0.59,并优化本地用户检查逻辑

This commit is contained in:
xiongxiao
2026-02-22 00:07:01 +08:00
parent c00062d704
commit e377557587
9 changed files with 172 additions and 129 deletions

View File

@@ -4,8 +4,7 @@ include:
.common_env: &common_env .common_env: &common_env
env: env:
TO_REPO: kevisual/cli USERNAME: root
TO_URL: git.xiongxiao.me
imports: imports:
- https://cnb.cool/kevisual/env/-/blob/main/.env.development - https://cnb.cool/kevisual/env/-/blob/main/.env.development
@@ -16,29 +15,6 @@ $:
services: services:
- vscode - vscode
- docker - docker
env: !reference [.common_env, env]
imports: !reference [.common_env, imports] imports: !reference [.common_env, imports]
# 开发环境启动后会执行的任务 stages: !reference [.dev_template, stages]
# stages:
# - name: pnpm install
# script: pnpm install
stages: !reference [.dev_tempalte, stages]
.common_sync_to_gitea: &common_sync_to_gitea
- <<: *common_env
services: !reference [.common_sync_to_gitea_template, services]
stages: !reference [.common_sync_to_gitea_template, stages]
.common_sync_from_gitea: &common_sync_from_gitea
- <<: *common_env
services: !reference [.common_sync_from_gitea_template, services]
stages: !reference [.common_sync_from_gitea_template, stages]
main:
web_trigger_sync_to_gitea:
- <<: *common_sync_to_gitea
web_trigger_sync_from_gitea:
- <<: *common_sync_from_gitea
api_trigger_sync_to_gitea:
- <<: *common_sync_to_gitea
api_trigger_sync_from_gitea:
- <<: *common_sync_from_gitea

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.58", "@kevisual/api": "^0.0.59",
"@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",

View File

@@ -37,6 +37,23 @@ export class AssistantApp extends Manager {
this.config = config; this.config = config;
this.resolver = new ModuleResolver(config.configPath.configDir); this.resolver = new ModuleResolver(config.configPath.configDir);
} }
async init(opts?: { isServer?: boolean }) {
const manager = this;
await manager.load({ runtime: 'client' });
console.log('Assistant App Loaded');
await manager.checkLocalUser();
const token = await assistantQuery.getToken();
if (token) {
console.log('用户已登录,正在初始化远程应用连接...');
await manager.initRemoteApp({ token });
await manager.initRemoteApp();
await manager.initRouterProxyLightApp();
}
await manager.initRouterProxyApp();
if (opts?.isServer) {
await manager.initRoutes();
}
}
async pageList() { async pageList() {
const pages = await glob(['*/*/package.json'], { const pages = await glob(['*/*/package.json'], {
cwd: this.pagesPath, cwd: this.pagesPath,
@@ -99,7 +116,11 @@ export class AssistantApp extends Manager {
} }
let token = opts?.token; let token = opts?.token;
if (!token) { if (!token) {
token = await assistantQuery.queryLogin.getToken(); token = await assistantQuery.getToken();
}
if (!token) {
logger.error('[remote-app] cli当前未登录无法连接远程app');
return;
} }
let shareUrl = share?.url; let shareUrl = share?.url;
if (!shareUrl) { if (!shareUrl) {
@@ -161,11 +182,10 @@ export class AssistantApp extends Manager {
* - lightcode: 轻代码模块配置 * - lightcode: 轻代码模块配置
* @returns * @returns
*/ */
async initRouterApp() { async initRouterProxyApp() {
const config = this.config.getConfig(); const config = this.config.getConfig();
const routerProxy = config?.router?.proxy || []; let routerProxy = config?.router?.proxy || [];
const base = config.router?.base ?? false; const base = config.router?.base ?? false;
const lightcode = config.router?.lightcode ?? true;
if (base) { if (base) {
routerProxy.push({ routerProxy.push({
type: 'router', type: 'router',
@@ -174,42 +194,13 @@ export class AssistantApp extends Manager {
} }
}) })
} }
if (lightcode) { routerProxy = routerProxy.filter(item => item.type === 'router');
routerProxy.push({
type: 'lightcode',
lightcode: {
id: 'main',
sync: 'remote',
rootPath: path.join(this.config.configPath.appsDir, 'light-code', 'code'),
}
})
}
if (routerProxy.length === 0) { if (routerProxy.length === 0) {
return return
} }
for (const proxyInfo of routerProxy) { for (const proxyInfo of routerProxy) {
if (proxyInfo.type !== 'router' && proxyInfo.type !== 'lightcode') { if (proxyInfo.type !== 'router') {
console.warn('路由的type必须是"router", 或者lightcode'); console.warn('路由的type必须是"router"');
continue;
}
if (proxyInfo.type === 'lightcode') {
const schema = z.object({
rootPath: z.string().describe('light-code 代码存放路径'),
sync: z.enum(['remote', 'local', 'both']).describe('同步方式remote: 仅从远程拉取local: 仅上传本地代码both: 双向同步').default('remote'),
});
const parseRes = schema.safeParse(proxyInfo.lightcode);
if (!parseRes.success) {
console.warn('lightcode 配置错误', parseRes.error);
continue;
}
const lightcodeConfig = parseRes.data;
initLightCode({
router: this.mainApp,
config: this.config,
sync: lightcodeConfig.sync,
rootPath: lightcodeConfig.rootPath,
});
continue; continue;
} }
const url = proxyInfo.router!.url; const url = proxyInfo.router!.url;
@@ -236,6 +227,49 @@ export class AssistantApp extends Manager {
} }
} }
} }
async initRouterProxyLightApp() {
const config = this.config.getConfig();
let routerProxy = config?.router?.proxy || [];
const lightcode = config.router?.lightcode ?? true;
if (lightcode) {
routerProxy.push({
type: 'lightcode',
lightcode: {
id: 'main',
sync: 'remote',
rootPath: path.join(this.config.configPath.appsDir, 'light-code', 'code'),
}
})
}
routerProxy = routerProxy.filter(item => item.type === 'lightcode');
if (routerProxy.length === 0) {
return
}
for (const proxyInfo of routerProxy) {
if (proxyInfo.type !== 'lightcode') {
console.warn('路由的type必须是"lightcode"');
continue;
}
const schema = z.object({
rootPath: z.string().describe('light-code 代码存放路径'),
sync: z.enum(['remote', 'local', 'both']).describe('同步方式remote: 仅从远程拉取local: 仅上传本地代码both: 双向同步').default('remote'),
});
const parseRes = schema.safeParse(proxyInfo.lightcode);
if (!parseRes.success) {
console.warn('lightcode 配置错误', parseRes.error);
continue;
}
const lightcodeConfig = parseRes.data;
await initLightCode({
router: this.mainApp,
config: this.config,
sync: lightcodeConfig.sync,
rootPath: lightcodeConfig.rootPath,
});
}
}
/** /**
* 动态加载文件插件模块的应用模块 * 动态加载文件插件模块的应用模块
* @info 不需要登录 * @info 不需要登录
@@ -265,34 +299,49 @@ export class AssistantApp extends Manager {
const checkLocalUser = async (opts: { assistantApp: AssistantApp }) => { const checkLocalUser = async (opts: { assistantApp: AssistantApp }) => {
const { assistantApp } = opts; const { assistantApp } = opts;
const config = assistantApp.config.getConfig(); const config = assistantApp.config.getConfig();
const auth = config?.auth; const auth = config?.auth || {};
let checkCNB = false; const isLogin = await assistantQuery.queryLogin.getToken();
if (!auth?.username) { logger.log('[assistant] 正在检查本地用户登录状态...', auth, '是否已登录', !!isLogin);
checkCNB = true;
// 没有登录过自动检测ci进行登录 const saveAuth = (auth: typeof config.auth, opts: { appId?: string, username: string; share: 'protected' | 'private' }) => {
// 检测条件1环境变量中存在 CNB_TOKEN auth.username = opts.username;
} else { auth.share = opts.share;
let temp = await assistantQuery.getToken() const app = config?.app || {};
logger.info('[assistant] 当前登录用户', auth.username, 'token有效性检查结果', !!temp); if (!app?.id) {
app.id = opts.appId || 'dev-cnb'
}
assistantApp.config.setConfig({
auth,
app
});
} }
const cnbToken = useKey('CNB_TOKEN'); if (!auth?.username && isLogin) {
if (!checkCNB && cnbToken) { // 没有登录过自动检测ci进行登录
// 检测条件1环境变量中存在 CNB_API_KEY
// 检测条件2本地没有登录过
const userInfo = await assistantQuery.queryLogin.checkLocalUser()
saveAuth(auth, { username: userInfo.username, share: 'protected' })
return;
}
if (isLogin) return;
// 没有登录,尝试根据环境变量进行登录
// 尝试使用 CNB_API_KEY 登录, 并设置管理员用户
const cnbToken = useKey('CNB_API_KEY');
if (cnbToken) {
logger.info('[cnb]检测到 CNB_API_KEY正在尝试使用 CNB_API_KEY 登录...');
const res = await assistantQuery.queryLogin.loginByCnb({ cnbToken }) const res = await assistantQuery.queryLogin.loginByCnb({ cnbToken })
if (res.code === 200) { if (res.code === 200) {
logger.info('CNB登录成功用户信息已更新');
const userInfo = await assistantQuery.queryLogin.checkLocalUser() const userInfo = await assistantQuery.queryLogin.checkLocalUser()
auth.username = userInfo.username; saveAuth(auth, { username: userInfo.username, share: 'protected' })
auth.share = 'protected' return
const app = config?.app || {};
if (!app?.id) {
app.id = 'dev-cnb'
}
assistantApp.config.setConfig({
auth,
app
});
} else { } else {
console.error('CNB登录失败无法获取用户信息', res); logger.error('CNB登录失败无法获取用户信息', res);
} }
} }
const kevisualToken = useKey('KEVISUAL_TOKEN');
if (kevisualToken) {
logger.info('[cnb]检测到 KEVISUAL_TOKEN正在尝试使用 KEVISUAL_TOKEN 登录...');
const res = await assistantQuery.queryLogin.refreshLoginUser(kevisualToken)
}
} }

View File

@@ -37,10 +37,6 @@ export class AssistantQuery {
} }
async getToken() { async getToken() {
const token = await this.queryLogin.getToken(); const token = await this.queryLogin.getToken();
if (!token) return '';
const isExpired = await this.queryLogin.checkTokenValid()
console.log('Token 是否过期', isExpired, token);
console.log('info', this.queryLogin.cacheStore.cacheData)
return token; return token;
} }
} }

View File

@@ -45,11 +45,15 @@ type LightCodeFile = {
id?: string, code?: string, hash?: string, filepath: string id?: string, code?: string, hash?: string, filepath: string
} }
export const initLightCode = async (opts: Opts) => { export const initLightCode = async (opts: Opts) => {
const token = await assistantQuery.getToken();
if (!token) {
console.error('[light-code] 当前未登录,无法初始化 light-code');
return;
}
// 注册 light-code 路由 // 注册 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 = await assistantQuery.getToken(); console.log('初始化 light-code 路由');
const query = config.query; const query = config.query;
const sync = opts.sync ?? 'remote'; const sync = opts.sync ?? 'remote';
if (!config || !app) { if (!config || !app) {

View File

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

40
assistant/src/test/cnb.ts Normal file
View File

@@ -0,0 +1,40 @@
import { CNB } from '@kevisual/cnb'
import { useKey } from '@kevisual/context'
import { QueryLoginNode } from '@kevisual/api/query-login-node'
import { Query } from '@kevisual/query'
const queryLogin = new QueryLoginNode({
query: new Query({ url: 'https://kevisual.cn/api/router' })
})
await queryLogin.cacheStore.init()
const cnb = new CNB({
token: useKey('CNB_TOKEN'),
})
// export const cnbLogin = async () => {
// const userInfo = await cnb.user.getUser()
// console.log('CNB用户信息', userInfo);
// }
// cnbLogin()
const testCnbLogin = async () => {
const res = await queryLogin.loginByCnb({
cnbToken: useKey('CNB_TOKEN') || '',
})
console.log('CNB登录结果', res);
if (res.code === 200) {
const userInfo = await queryLogin.checkLocalUser()
console.log('CNB登录成功用户信息', userInfo);
} else {
console.log('CNB登录失败', res);
}
}
// testCnbLogin()
const getCNBLocalUser = async () => {
const res = await queryLogin.checkLocalUser()
console.log('查询本地用户信息', res);
const token = await queryLogin.getToken()
console.log('检查token是否过期', token);
}
getCNBLocalUser()

View File

@@ -59,7 +59,7 @@
"unstorage": "^1.17.4" "unstorage": "^1.17.4"
}, },
"devDependencies": { "devDependencies": {
"@kevisual/api": "^0.0.58", "@kevisual/api": "^0.0.59",
"@kevisual/cnb": "^0.0.28", "@kevisual/cnb": "^0.0.28",
"@kevisual/dts": "^0.0.4", "@kevisual/dts": "^0.0.4",
"@kevisual/load": "^0.0.6", "@kevisual/load": "^0.0.6",

39
pnpm-lock.yaml generated
View File

@@ -58,8 +58,8 @@ importers:
version: 1.17.4(idb-keyval@6.2.2)(ioredis@5.9.3(supports-color@10.2.2)) version: 1.17.4(idb-keyval@6.2.2)(ioredis@5.9.3(supports-color@10.2.2))
devDependencies: devDependencies:
'@kevisual/api': '@kevisual/api':
specifier: ^0.0.58 specifier: ^0.0.59
version: 0.0.58(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) version: 0.0.59(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@kevisual/cnb': '@kevisual/cnb':
specifier: ^0.0.28 specifier: ^0.0.28
version: 0.0.28(dotenv@17.3.1)(idb-keyval@6.2.2)(ioredis@5.9.3) version: 0.0.28(dotenv@17.3.1)(idb-keyval@6.2.2)(ioredis@5.9.3)
@@ -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.58 specifier: ^0.0.59
version: 0.0.58(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) version: 0.0.59(@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
@@ -1290,8 +1290,8 @@ packages:
'@kevisual/api@0.0.28': '@kevisual/api@0.0.28':
resolution: {integrity: sha512-WQluRlu2qGM1qktIhPLODie8x382a6jEMfFOcay/rnkCgXK0BRpnqOKwlX7IMLdMqka7GY/BD69kSMnK1Exf5g==} resolution: {integrity: sha512-WQluRlu2qGM1qktIhPLODie8x382a6jEMfFOcay/rnkCgXK0BRpnqOKwlX7IMLdMqka7GY/BD69kSMnK1Exf5g==}
'@kevisual/api@0.0.58': '@kevisual/api@0.0.59':
resolution: {integrity: sha512-ontJswmD5LS4EjYZDGF/SI1oYI1/zCM6ovC8rviNzxI22294yQ5y8Lb/rYV2qsKaxJbC3uuOjjsjPWap0nSvAQ==} resolution: {integrity: sha512-2w6GBG2mS92dz8afB0hLfjTw8lBGD5oXU5bw/QglFugHHp24fISZkEW1Hc+jP/jOiYlMzphws2/31DIXdDoGkg==}
'@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==}
@@ -3036,15 +3036,6 @@ packages:
supports-color: supports-color:
optional: true optional: true
debug@4.4.0:
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
debug@4.4.3: debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@@ -6609,7 +6600,7 @@ snapshots:
fuse.js: 7.1.0 fuse.js: 7.1.0
nanoid: 5.1.6 nanoid: 5.1.6
'@kevisual/api@0.0.58(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': '@kevisual/api@0.0.59(@types/react@19.2.10)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies: dependencies:
'@kevisual/context': 0.0.8 '@kevisual/context': 0.0.8
'@kevisual/js-filter': 0.0.5 '@kevisual/js-filter': 0.0.5
@@ -8850,12 +8841,6 @@ snapshots:
optionalDependencies: optionalDependencies:
supports-color: 10.2.2 supports-color: 10.2.2
debug@4.4.0(supports-color@10.2.2):
dependencies:
ms: 2.1.3
optionalDependencies:
supports-color: 10.2.2
debug@4.4.3(supports-color@10.2.2): debug@4.4.3(supports-color@10.2.2):
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@@ -10456,7 +10441,7 @@ snapshots:
pm2-axon-rpc@0.7.1(supports-color@10.2.2): pm2-axon-rpc@0.7.1(supports-color@10.2.2):
dependencies: dependencies:
debug: 4.4.0(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -10464,7 +10449,7 @@ snapshots:
dependencies: dependencies:
amp: 0.3.1 amp: 0.3.1
amp-message: 0.1.2 amp-message: 0.1.2
debug: 4.4.0(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2)
escape-string-regexp: 4.0.0 escape-string-regexp: 4.0.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -10481,7 +10466,7 @@ snapshots:
pm2-sysmonit@1.2.8(supports-color@10.2.2): pm2-sysmonit@1.2.8(supports-color@10.2.2):
dependencies: dependencies:
async: 3.2.6 async: 3.2.6
debug: 4.4.0(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2)
pidusage: 2.0.21 pidusage: 2.0.21
systeminformation: 5.25.11 systeminformation: 5.25.11
tx2: 1.0.5 tx2: 1.0.5
@@ -10557,7 +10542,7 @@ snapshots:
proxy-agent@6.4.0(supports-color@10.2.2): proxy-agent@6.4.0(supports-color@10.2.2):
dependencies: dependencies:
agent-base: 7.1.3 agent-base: 7.1.3
debug: 4.4.0(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2)
http-proxy-agent: 7.0.2(supports-color@10.2.2) http-proxy-agent: 7.0.2(supports-color@10.2.2)
https-proxy-agent: 7.0.6(supports-color@10.2.2) https-proxy-agent: 7.0.6(supports-color@10.2.2)
lru-cache: 7.18.3 lru-cache: 7.18.3
@@ -10832,7 +10817,7 @@ snapshots:
require-in-the-middle@5.2.0(supports-color@10.2.2): require-in-the-middle@5.2.0(supports-color@10.2.2):
dependencies: dependencies:
debug: 4.4.0(supports-color@10.2.2) debug: 4.4.3(supports-color@10.2.2)
module-details-from-path: 1.0.3 module-details-from-path: 1.0.3
resolve: 1.22.8 resolve: 1.22.8
transitivePeerDependencies: transitivePeerDependencies: