feat: update ev cli
This commit is contained in:
		| @@ -21,3 +21,4 @@ export const app = new App({ | ||||
|     httpsKey: httpsPem.key, | ||||
|   }, | ||||
| }); | ||||
|  | ||||
|   | ||||
| @@ -93,7 +93,7 @@ const pageListCommand = new Command('page-list') | ||||
|   .action(async (opts) => { | ||||
|     const manager = new AssistantApp(assistantConfig); | ||||
|     await manager.loadConfig(); | ||||
|     const showInfos = manager.pageList(); | ||||
|     const showInfos = await manager.pageList(); | ||||
|     if (opts.all) { | ||||
|       console.log('Installed Pages:', showInfos); | ||||
|     } else { | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import { logger } from '@/module/logger.ts'; | ||||
| import { program, Command, assistantConfig } from '@/program.ts'; | ||||
| import { AppDownload } from '@/services/app/index.ts'; | ||||
|  | ||||
| @@ -17,9 +18,12 @@ const downloadCommand = new Command('download') | ||||
|     const registry = options.registry || assistantConfig.getRegistry(); | ||||
|     // console.log('registry', registry); | ||||
|     const app = new AppDownload(assistantConfig); | ||||
|     let info = ''; | ||||
|     if (id) { | ||||
|       await app.downloadApp({ id, type, registry, force, yes }); | ||||
|       const msg = await app.downloadApp({ id, type, registry, force, yes }); | ||||
|       info = String(msg); | ||||
|     } | ||||
|     logger.debug(info); | ||||
|   }); | ||||
|  | ||||
| appManagerCommand.addCommand(downloadCommand); | ||||
| @@ -31,8 +35,11 @@ const deleteCommand = new Command('delete') | ||||
|   .action(async (options) => { | ||||
|     const { id, type } = options; | ||||
|     const app = new AppDownload(assistantConfig); | ||||
|     let info = ''; | ||||
|     if (id) { | ||||
|       await app.deleteApp({ id, type }); | ||||
|       const msg = await app.deleteApp({ id, type }); | ||||
|       info = String(msg); | ||||
|     } | ||||
|     logger.debug(info); | ||||
|   }); | ||||
| appManagerCommand.addCommand(deleteCommand); | ||||
|   | ||||
| @@ -22,8 +22,8 @@ export class AssistantApp extends Manager { | ||||
|     this.pagesPath = pagesPath; | ||||
|     this.config = config; | ||||
|   } | ||||
|   pageList() { | ||||
|     const pages = glob.sync('*/*/package.json', { | ||||
|   async pageList() { | ||||
|     const pages = await glob(['*/*/package.json'], { | ||||
|       cwd: this.pagesPath, | ||||
|       onlyFiles: true, | ||||
|     }); | ||||
| @@ -35,9 +35,32 @@ export class AssistantApp extends Manager { | ||||
|         user, | ||||
|         app, | ||||
|         version: content?.version, | ||||
|         title: content?.title || '', | ||||
|         description: content?.description || '', | ||||
|         content, | ||||
|       }; | ||||
|     }); | ||||
|     return pagesParse; | ||||
|   } | ||||
|   async getPageAndAppList() { | ||||
|     const root = this.config.configPath.configDir; | ||||
|     const pages = await glob([root + '/apps/*/package.json', root + '/pages/*/*/package.json'], { | ||||
|       cwd: root, | ||||
|       onlyFiles: true, | ||||
|     }); | ||||
|     const pagesParse = pages.map((page) => { | ||||
|       const relativePath = path.relative(root, page); | ||||
|       const contentStr = fs.readFileSync(path.join(page), 'utf-8'); | ||||
|       const content = parseIfJson(contentStr); | ||||
|       if (!content.appType) { | ||||
|         const isWeb = relativePath.startsWith('pages/'); | ||||
|         content.appType = isWeb ? 'web' : 'app'; | ||||
|       } | ||||
|       return { | ||||
|         ...content, | ||||
|         filepath: relativePath, | ||||
|       }; | ||||
|     }); | ||||
|     return pagesParse; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { Logger } from '@kevisual/logger'; | ||||
| const level = process.env.LOG_LEVEL || 'info'; | ||||
| const logger = new Logger({ level: level as any }); | ||||
| export const logger = new Logger({ level: level as any }); | ||||
|  | ||||
| export const console = { | ||||
|   log: logger.info, | ||||
|   | ||||
| @@ -11,3 +11,13 @@ app | ||||
|     // | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'client', | ||||
|     key: 'version', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     ctx.body = 'v1.0.0'; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|   | ||||
							
								
								
									
										27
									
								
								assistant/src/routes/shop-install/define.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								assistant/src/routes/shop-install/define.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| import { QueryUtil } from '@kevisual/router/define'; | ||||
|  | ||||
| export const shopDefine = QueryUtil.create({ | ||||
|   getRegistry: { | ||||
|     path: 'shop', | ||||
|     key: 'get-registry', | ||||
|     description: '获取应用商店注册表信息', | ||||
|   }, | ||||
|  | ||||
|   listInstalled: { | ||||
|     path: 'shop', | ||||
|     key: 'list-installed', | ||||
|     description: '列出当前已安装的所有应用', | ||||
|   }, | ||||
|  | ||||
|   install: { | ||||
|     path: 'shop', | ||||
|     key: 'install', | ||||
|     description: '安装指定的应用,可以指定 id、type、force 和 yes 参数', | ||||
|   }, | ||||
|  | ||||
|   uninstall: { | ||||
|     path: 'shop', | ||||
|     key: 'uninstall', | ||||
|     description: '卸载指定的应用,可以指定 id 和 type 参数', | ||||
|   }, | ||||
| }); | ||||
| @@ -1,64 +1,69 @@ | ||||
| import { app } from '@/app.ts'; | ||||
| // import { getInstallList, installApp, uninstallApp } from '@/modules/install.ts'; | ||||
| const getInstallList = async () => { | ||||
|   return []; | ||||
| }; | ||||
| const installApp = async (pkg: string) => { | ||||
|   return { | ||||
|     code: 200, | ||||
|     message: 'success', | ||||
|     data: { | ||||
|       pkg, | ||||
|     }, | ||||
|   }; | ||||
| }; | ||||
| const uninstallApp = async (pkg: string) => { | ||||
|   return { | ||||
|     code: 200, | ||||
|     message: 'success', | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| import { app, assistantConfig } from '@/app.ts'; | ||||
| import { AppDownload } from '@/services/app/index.ts'; | ||||
| import { AssistantApp } from '@/module/assistant/index.ts'; | ||||
| import { shopDefine } from './define.ts'; | ||||
| app | ||||
|   .route({ | ||||
|     path: 'shop', | ||||
|     key: 'list-installed', | ||||
|     ...shopDefine.get('getRegistry'), | ||||
|     middleware: ['auth'], | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     // https://localhost:51015/client/router?path=shop&key=list-installed | ||||
|     const list = await getInstallList(); | ||||
|     ctx.body = list; | ||||
|     const registry = assistantConfig.getRegistry(); | ||||
|     assistantConfig.checkMounted(); | ||||
|     ctx.body = registry; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'shop', | ||||
|     key: 'install', | ||||
|     ...shopDefine.get('listInstalled'), | ||||
|     middleware: ['auth'], | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     const manager = new AssistantApp(assistantConfig); | ||||
|     await manager.loadConfig(); | ||||
|     const data = await manager.getPageAndAppList(); | ||||
|     ctx.body = data; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     ...shopDefine.get('install'), | ||||
|     middleware: ['auth'], | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     // https://localhost:51015/client/router?path=shop&key=install | ||||
|     const { pkg } = ctx.query.data; | ||||
|     const res = await installApp(pkg); | ||||
|     if (res.code !== 200) { | ||||
|       ctx.throw(res.code, res.message); | ||||
|     const options = ctx.query?.data || {}; | ||||
|     const { id, type, force, yes } = options; | ||||
|     assistantConfig.checkMounted(); | ||||
|     const registry = options.registry || assistantConfig.getRegistry(); | ||||
|     // console.log('registry', registry); | ||||
|     const app = new AppDownload(assistantConfig); | ||||
|     let info = ''; | ||||
|     if (id) { | ||||
|       const msg = await app.downloadApp({ id, type, registry, force, yes }); | ||||
|       info = String(msg); | ||||
|     } | ||||
|     ctx.body = res; | ||||
|     ctx.body = { info }; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'shop', | ||||
|     key: 'uninstall', | ||||
|     ...shopDefine.get('uninstall'), | ||||
|     middleware: ['auth'], | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     // https://localhost:51015/client/router?path=shop&key=uninstall | ||||
|     const { pkg } = ctx.query.data; | ||||
|     const res = await uninstallApp(pkg); | ||||
|     ctx.body = res; | ||||
|     const options = ctx.query?.data || {}; | ||||
|     const { id, type, yes } = options; | ||||
|     const app = new AppDownload(assistantConfig); | ||||
|     let info = ''; | ||||
|     if (id) { | ||||
|       const msg = await app.deleteApp({ id, type, yes }); | ||||
|       info = String(msg); | ||||
|     } | ||||
|     ctx.body = { info }; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|   | ||||
| @@ -48,14 +48,19 @@ type DeleteAppOptions = { | ||||
|   id: string; | ||||
|   type?: appType; | ||||
|   appName?: string; | ||||
|   yes?: boolean; | ||||
| }; | ||||
|  | ||||
| export class AppDownload { | ||||
|   config: AssistantConfig; | ||||
|   constructor(config: AssistantConfig) { | ||||
|     this.config = config; | ||||
|   } | ||||
|   async getRegistry() { | ||||
|     return this.config.getRegistry(); | ||||
|   } | ||||
|   async downloadApp(opts: DownloadAppOptions) { | ||||
|     const { id, type = 'web', force } = opts; | ||||
|     const { id, type = 'web', force, yes } = opts; | ||||
|     const configDir = this.config.configDir; | ||||
|     this.config?.checkMounted(); | ||||
|     const appsDir = this.config.configPath?.appsDir; | ||||
| @@ -100,7 +105,7 @@ export class AppDownload { | ||||
|     return confirm; | ||||
|   } | ||||
|   async deleteApp(opts: DeleteAppOptions) { | ||||
|     const { id, type = 'web' } = opts; | ||||
|     const { id, type = 'web', yes = false } = opts; | ||||
|     const appName = opts?.appName || id.split('/').pop(); | ||||
|     this.config?.checkMounted(); | ||||
|     const appsDir = this.config.configPath?.appsDir; | ||||
| @@ -119,11 +124,13 @@ export class AppDownload { | ||||
|       deletePath = appPath; | ||||
|     } | ||||
|     if (deletePath && checkFileExists(deletePath)) { | ||||
|       if (!yes) { | ||||
|         const confirm = await this.confirm(`是否删除 ${deletePath} 应用?`); | ||||
|         if (!confirm) { | ||||
|           console.log('取消删除应用'); | ||||
|           return; | ||||
|         } | ||||
|       } | ||||
|       fs.rmSync(deletePath, { recursive: true }); | ||||
|       isDelete = true; | ||||
|       console.log(`删除应用成功: ${deletePath}`); | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { fileProxy, httpProxy, createApiProxy, wsProxy } from '@/module/assistan | ||||
| import http from 'http'; | ||||
| import { LocalProxy } from './local-proxy.ts'; | ||||
| import { assistantConfig, app } from '@/app.ts'; | ||||
| import { log } from '@/module/logger.ts'; | ||||
| import { log, logger } from '@/module/logger.ts'; | ||||
| const localProxy = new LocalProxy({ | ||||
|   assistantConfig, | ||||
| }); | ||||
| @@ -21,6 +21,7 @@ export const proxyRoute = async (req: http.IncomingMessage, res: http.ServerResp | ||||
|     return; | ||||
|   } | ||||
|   if (pathname.startsWith('/client')) { | ||||
|     logger.info('url', { url: req.url }); | ||||
|     console.debug('handle by router'); | ||||
|     return; | ||||
|   } | ||||
| @@ -74,7 +75,7 @@ export const proxyRoute = async (req: http.IncomingMessage, res: http.ServerResp | ||||
|       indexPath: localProxyProxy.indexPath, | ||||
|     }); | ||||
|   } | ||||
|   const creatCenterProxy = createApiProxy(_assistantConfig?.pageApi || 'https://kevisual.cn', ['/root']); | ||||
|   const creatCenterProxy = createApiProxy(_assistantConfig?.pageApi || 'https://kevisual.cn', ['/root', '/' + _user]); | ||||
|   const centerProxy = creatCenterProxy.find((item) => pathname.startsWith(item.path)); | ||||
|   if (centerProxy) { | ||||
|     return httpProxy(req, res, { | ||||
|   | ||||
							
								
								
									
										12
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "@kevisual/envision-cli", | ||||
|   "version": "0.0.49", | ||||
|   "version": "0.0.51", | ||||
|   "description": "envision command tools", | ||||
|   "main": "dist/app.mjs", | ||||
|   "type": "module", | ||||
| @@ -39,20 +39,20 @@ | ||||
|   "author": "abearxiong", | ||||
|   "dependencies": { | ||||
|     "micromatch": "^4.0.8", | ||||
|     "pm2": "^6.0.5" | ||||
|     "pm2": "^6.0.6" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@kevisual/load": "^0.0.6", | ||||
|     "@kevisual/logger": "^0.0.3", | ||||
|     "@kevisual/query": "0.0.17", | ||||
|     "@kevisual/query": "0.0.18", | ||||
|     "@kevisual/query-login": "0.0.5", | ||||
|     "@types/bun": "^1.2.13", | ||||
|     "@types/crypto-js": "^4.2.2", | ||||
|     "@types/jsonwebtoken": "^9.0.9", | ||||
|     "@types/micromatch": "^4.0.9", | ||||
|     "@types/node": "^22.15.17", | ||||
|     "@types/node": "^22.15.18", | ||||
|     "chalk": "^5.4.1", | ||||
|     "commander": "^13.1.0", | ||||
|     "commander": "^14.0.0", | ||||
|     "crypto-js": "^4.2.0", | ||||
|     "fast-glob": "^3.3.3", | ||||
|     "filesize": "^10.1.6", | ||||
| @@ -60,7 +60,7 @@ | ||||
|     "ignore": "^7.0.4", | ||||
|     "inquirer": "^12.6.1", | ||||
|     "jsonwebtoken": "^9.0.2", | ||||
|     "rollup": "^4.40.2", | ||||
|     "rollup": "^4.41.0", | ||||
|     "rollup-plugin-dts": "^6.2.1", | ||||
|     "tar": "^7.4.3", | ||||
|     "zustand": "^5.0.4" | ||||
|   | ||||
							
								
								
									
										806
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										806
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -7,11 +7,18 @@ import { getConfig } from '@/module/get-config.ts'; | ||||
| import fs from 'fs'; | ||||
| import inquirer from 'inquirer'; | ||||
| import { checkPnpm } from '@/uitls/npm.ts'; | ||||
|  | ||||
| const parseIfJson = (str: string) => { | ||||
|   try { | ||||
|     return JSON.parse(str); | ||||
|   } catch (e) { | ||||
|     return {}; | ||||
|   } | ||||
| }; | ||||
| const command = new Command('npm').description('npm command show publish and set .npmrc').action(async (options) => {}); | ||||
| const publish = new Command('publish') | ||||
|   .argument('[registry]') | ||||
|   .option('-p --proxy', 'proxy') | ||||
|   .option('-t, --tag', 'tag') | ||||
|   .description('publish npm') | ||||
|   .action(async (registry, options) => { | ||||
|     const answer = await inquirer.prompt([ | ||||
| @@ -53,15 +60,12 @@ const publish = new Command('publish') | ||||
|       switch (registry) { | ||||
|         case 'me': | ||||
|           cmd = 'npm publish --registry https://npm.xiongxiao.me'; | ||||
|           console.log(chalk.green(cmd)); | ||||
|           break; | ||||
|         case 'npm': | ||||
|           cmd = 'npm publish --registry https://registry.npmjs.org'; | ||||
|           console.log(chalk.green(cmd)); | ||||
|           break; | ||||
|         default: | ||||
|           cmd = 'npm publish --registry https://npm.xiongxiao.me'; | ||||
|           console.log(chalk.green(cmd)); | ||||
|           break; | ||||
|       } | ||||
|       if (fileIsExist(packageJson)) { | ||||
| @@ -72,6 +76,20 @@ const publish = new Command('publish') | ||||
|             [key]: config[key], | ||||
|           }; | ||||
|         }, {}); | ||||
|         const pkg = fs.readFileSync(packageJson, 'utf-8'); | ||||
|         const pkgJson = parseIfJson(pkg); | ||||
|         const version = pkgJson?.version as string; | ||||
|         if (version && options?.tag) { | ||||
|           let tag = String(version).split('-')[1] || ''; | ||||
|           if (tag) { | ||||
|             if (tag.includes('.')) { | ||||
|               tag = tag.split('.')[0]; | ||||
|             } | ||||
|             cmd = `${cmd} --tag ${tag}`; | ||||
|           } | ||||
|         } | ||||
|         console.log(chalk.green(cmd)); | ||||
|  | ||||
|         const child = spawn(cmd, { | ||||
|           shell: true, | ||||
|           cwd: execPath, | ||||
|   | ||||
| @@ -94,6 +94,29 @@ const checkDelete = async (opts?: { force?: boolean; dir?: string; yes?: boolean | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| export const rewritePkg = (packagePath: string, pkg: Package) => { | ||||
|   const readJsonFile = (filePath: string) => { | ||||
|     try { | ||||
|       return JSON.parse(fs.readFileSync(filePath, 'utf-8')); | ||||
|     } catch (error) { | ||||
|       return {}; | ||||
|     } | ||||
|   }; | ||||
|   try { | ||||
|     const dirname = path.dirname(packagePath); | ||||
|     if (!fs.existsSync(dirname)) { | ||||
|       fs.mkdirSync(dirname, { recursive: true }); | ||||
|     } | ||||
|     const json = readJsonFile(packagePath); | ||||
|     json.id = pkg?.id; | ||||
|     json.appInfo = pkg; | ||||
|  | ||||
|     fs.writeFileSync(packagePath, JSON.stringify(json, null, 2)); | ||||
|   } catch (error) { | ||||
|     fs.writeFileSync(packagePath, JSON.stringify({ appInfo: pkg, id: pkg?.id }, null, 2)); | ||||
|   } | ||||
|   return pkg; | ||||
| }; | ||||
| type InstallAppOpts = { | ||||
|   appDir?: string; | ||||
|   kevisualUrl?: string; | ||||
| @@ -118,7 +141,6 @@ export const installApp = async (app: Package, opts: InstallAppOpts = {}) => { | ||||
|   try { | ||||
|     let files = _app.data.files || []; | ||||
|     const version = _app.version; | ||||
|     let hasPackage = false; | ||||
|     const user = _app.user; | ||||
|     const key = _app.key; | ||||
|     const downloadDirPath = appType === 'web' ? path.join(appDir, user, key) : path.join(appDir); | ||||
| @@ -128,9 +150,6 @@ export const installApp = async (app: Package, opts: InstallAppOpts = {}) => { | ||||
|       .filter((file: any) => file?.path) | ||||
|       .map((file: any) => { | ||||
|         const name = file?.name || ''; | ||||
|         if (name.startsWith('package.json')) { | ||||
|           hasPackage = true; | ||||
|         } | ||||
|         const noVersionPath = file.path.replace(`/${version}`, ''); | ||||
|         let downloadPath = noVersionPath; | ||||
|         let downloadUrl = ''; | ||||
| @@ -150,15 +169,7 @@ export const installApp = async (app: Package, opts: InstallAppOpts = {}) => { | ||||
|       }); | ||||
|     const downloadTasks: DownloadTask[] = downFiles as any; | ||||
|     console.log('downloadTasks', downloadTasks); | ||||
|     if (!hasPackage) { | ||||
|       console.log('没有package.json文件, 生成一个'); | ||||
|       const pkg = { ..._app }; | ||||
|       if (pkg.data) { | ||||
|         delete pkg.data.permission; | ||||
|       } | ||||
|       fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2)); | ||||
|     } | ||||
|     // return; | ||||
|  | ||||
|     for (const file of downloadTasks) { | ||||
|       const downloadPath = file.downloadPath; | ||||
|       const downloadUrl = file.downloadUrl; | ||||
| @@ -186,6 +197,7 @@ export const installApp = async (app: Package, opts: InstallAppOpts = {}) => { | ||||
|     //   fs.writeFileSync(path.join(appDir, `${user}/${key}/index.html`), JSON.stringify(app, null, 2)); | ||||
|     // } | ||||
|     _app.data.files = files; | ||||
|     rewritePkg(packagePath, _app); | ||||
|     return { | ||||
|       code: 200, | ||||
|       data: _app, | ||||
|   | ||||
 Submodule submodules/kevisual-query-login updated: 557cd99b20...0a0ffbdb23
									
								
							
		Reference in New Issue
	
	Block a user