generated from tailored/router-template
	base module
This commit is contained in:
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -11,4 +11,5 @@ cache-file | ||||
|  | ||||
| /apps | ||||
|  | ||||
| logs | ||||
| logs | ||||
| root/ | ||||
|   | ||||
							
								
								
									
										3
									
								
								.npmrc
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								.npmrc
									
									
									
									
									
								
							| @@ -1,2 +1,3 @@ | ||||
| //npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN} | ||||
| //registry.npmjs.org/:_authToken=${NPM_TOKEN} | ||||
| //registry.npmjs.org/:_authToken=${NPM_TOKEN} | ||||
| ignore-workspace-root-check=true | ||||
							
								
								
									
										2
									
								
								assistant-module/.npmrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								assistant-module/.npmrc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| //npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN} | ||||
| //registry.npmjs.org/:_authToken=${NPM_TOKEN} | ||||
							
								
								
									
										49
									
								
								assistant-module/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								assistant-module/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | ||||
| { | ||||
|   "name": "@kevisual/assistant-module", | ||||
|   "version": "0.0.3", | ||||
|   "description": "assistant module", | ||||
|   "main": "dist/assistant-module.mjs", | ||||
|   "types": "dist/assistant-module.d.ts", | ||||
|   "scripts": { | ||||
|     "dev": "rollup -c -w", | ||||
|     "build": "npm run clean && rollup -c", | ||||
|     "clean": "rm -rf dist" | ||||
|   }, | ||||
|   "keywords": [], | ||||
|   "author": "abearxiong <xiongxiao@xiongxiao.me>", | ||||
|   "license": "MIT", | ||||
|   "type": "module", | ||||
|   "devDependencies": { | ||||
|     "@types/node": "^22.13.10", | ||||
|     "@types/send": "^0.17.4", | ||||
|     "@types/ws": "^8.18.0" | ||||
|   }, | ||||
|   "publishConfig": { | ||||
|     "access": "public" | ||||
|   }, | ||||
|   "files": [ | ||||
|     "dist" | ||||
|   ], | ||||
|   "exports": { | ||||
|     ".": { | ||||
|       "import": "./dist/assistant-module.mjs", | ||||
|       "types": "./dist/assistant-module.d.ts" | ||||
|     }, | ||||
|     "./proxy": { | ||||
|       "import": "./dist/assistant-proxy.mjs", | ||||
|       "types": "./dist/assistant-proxy.d.ts" | ||||
|     }, | ||||
|     "./assistant-config": { | ||||
|       "import": "./dist/assistant-config.mjs", | ||||
|       "types": "./dist/assistant-config.d.ts" | ||||
|     }, | ||||
|     "./assistant-process": { | ||||
|       "import": "./dist/assistant-process.mjs", | ||||
|       "types": "./dist/assistant-process.d.ts" | ||||
|     } | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "send": "^1.1.0", | ||||
|     "ws": "^8.18.1" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										29
									
								
								assistant-module/pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								assistant-module/pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| lockfileVersion: '9.0' | ||||
|  | ||||
| settings: | ||||
|   autoInstallPeers: true | ||||
|   excludeLinksFromLockfile: false | ||||
|  | ||||
| importers: | ||||
|  | ||||
|   .: | ||||
|     devDependencies: | ||||
|       '@types/node': | ||||
|         specifier: ^22.13.10 | ||||
|         version: 22.13.10 | ||||
|  | ||||
| packages: | ||||
|  | ||||
|   '@types/node@22.13.10': | ||||
|     resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==} | ||||
|  | ||||
|   undici-types@6.20.0: | ||||
|     resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} | ||||
|  | ||||
| snapshots: | ||||
|  | ||||
|   '@types/node@22.13.10': | ||||
|     dependencies: | ||||
|       undici-types: 6.20.0 | ||||
|  | ||||
|   undici-types@6.20.0: {} | ||||
							
								
								
									
										172
									
								
								assistant-module/rollup.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								assistant-module/rollup.config.mjs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| import resolve from '@rollup/plugin-node-resolve'; | ||||
| import commonjs from '@rollup/plugin-commonjs'; | ||||
| import json from '@rollup/plugin-json'; | ||||
| import path from 'path'; | ||||
| import esbuild from 'rollup-plugin-esbuild'; | ||||
| import alias from '@rollup/plugin-alias'; | ||||
| import replace from '@rollup/plugin-replace'; | ||||
| import dts from 'rollup-plugin-dts'; | ||||
| // @ts-ignore | ||||
| import pkgs from './package.json' with {type: 'json'}; | ||||
|  | ||||
| const isDev = process.env.NODE_ENV === 'development'; | ||||
| const input = './src/index.ts'; | ||||
| /** | ||||
|  * @type {import('rollup').RollupOptions} | ||||
|  */ | ||||
| const config = { | ||||
|   input, | ||||
|   output: { | ||||
|     dir: './dist', | ||||
|     entryFileNames: 'assistant-module.mjs', | ||||
|     chunkFileNames: '[name]-[hash].mjs', | ||||
|     format: 'esm', | ||||
|   }, | ||||
|   plugins: [ | ||||
|     replace({ | ||||
|       preventAssignment: true, // 防止意外赋值 | ||||
|       DEV_SERVER: JSON.stringify(isDev), // 替换 process.env.NODE_ENV | ||||
|       VERSION: JSON.stringify(pkgs.version), | ||||
|     }), | ||||
|     alias({ | ||||
|       // only esbuild needs to be configured | ||||
|       entries: [ | ||||
|         { find: '@', replacement: path.resolve('src') }, // 配置 @ 为 src 目录 | ||||
|         { find: 'http', replacement: 'node:http' }, | ||||
|         { find: 'https', replacement: 'node:https' }, | ||||
|         { find: 'fs', replacement: 'node:fs' }, | ||||
|         { find: 'path', replacement: 'node:path' }, | ||||
|         { find: 'crypto', replacement: 'node:crypto' }, | ||||
|         { find: 'zlib', replacement: 'node:zlib' }, | ||||
|         { find: 'stream', replacement: 'node:stream' }, | ||||
|         { find: 'net', replacement: 'node:net' }, | ||||
|         { find: 'tty', replacement: 'node:tty' }, | ||||
|         { find: 'tls', replacement: 'node:tls' }, | ||||
|         { find: 'buffer', replacement: 'node:buffer' }, | ||||
|         { find: 'timers', replacement: 'node:timers' }, | ||||
|         // { find: 'string_decoder', replacement: 'node:string_decoder' }, | ||||
|         { find: 'dns', replacement: 'node:dns' }, | ||||
|         { find: 'domain', replacement: 'node:domain' }, | ||||
|         { find: 'os', replacement: 'node:os' }, | ||||
|         { find: 'events', replacement: 'node:events' }, | ||||
|         { find: 'url', replacement: 'node:url' }, | ||||
|         { find: 'assert', replacement: 'node:assert' }, | ||||
|         { find: 'util', replacement: 'node:util' }, | ||||
|       ], | ||||
|     }), | ||||
|     resolve({ | ||||
|       preferBuiltins: true, // 强制优先使用内置模块 | ||||
|     }), | ||||
|     commonjs(), | ||||
|     esbuild({ | ||||
|       target: 'node22', // | ||||
|       minify: false, // 启用代码压缩 | ||||
|       tsconfig: 'tsconfig.json', | ||||
|     }), | ||||
|     json(), | ||||
|   ], | ||||
|   external: [ | ||||
|     /@kevisual\/router(\/.*)?/, //, // 路由 | ||||
|     /@kevisual\/use-config(\/.*)?/, // | ||||
|   ], | ||||
| }; | ||||
| const dtsConfig = [{ | ||||
|   input, | ||||
|   output: { | ||||
|     file: 'dist/assistant-module.d.ts', | ||||
|     format: 'esm', | ||||
|   }, | ||||
|   plugins: [dts()], | ||||
| }]; | ||||
|  | ||||
| const moduleConfig = { | ||||
|   input: './src/assistant-proxy.ts', | ||||
|   output: { | ||||
|     file: 'dist/assistant-proxy.mjs', | ||||
|     format: 'esm', | ||||
|   }, | ||||
|   plugins: [ | ||||
|     alias({ | ||||
|       entries: [{ find: '@', replacement: path.resolve('src') }], | ||||
|     }), | ||||
|     resolve({ | ||||
|       preferBuiltins: true, // 强制优先使用内置模块 | ||||
|     }), | ||||
|     commonjs(), | ||||
|     esbuild({ | ||||
|       target: 'node22', // | ||||
|     }), | ||||
|     json(), | ||||
|   ], | ||||
|  | ||||
| }; | ||||
| const moduleDtsConfig = [{ | ||||
|   input: './src/assistant-proxy.ts', | ||||
|   output: { | ||||
|     file: 'dist/assistant-proxy.d.ts', | ||||
|     format: 'esm', | ||||
|   }, | ||||
|   plugins: [dts()], | ||||
| }]; | ||||
|  | ||||
| const assistantConfigConfig = { | ||||
|   input: './src/assistant-config.ts', | ||||
|   output: { | ||||
|     file: 'dist/assistant-config.mjs', | ||||
|     format: 'esm', | ||||
|   }, | ||||
|   plugins: [ | ||||
|     alias({ | ||||
|       entries: [{ find: '@', replacement: path.resolve('src') }], | ||||
|     }), | ||||
|     resolve({ | ||||
|       preferBuiltins: true, // 强制优先使用内置模块 | ||||
|     }), | ||||
|     commonjs(), | ||||
|     esbuild({ | ||||
|       target: 'node22', // | ||||
|     }), | ||||
|     json(), | ||||
|   ], | ||||
| }; | ||||
| const assistantConfigDtsConfig = [{ | ||||
|   input: './src/assistant-config.ts', | ||||
|   output: { | ||||
|     file: 'dist/assistant-config.d.ts', | ||||
|     format: 'esm', | ||||
|   }, | ||||
|   plugins: [dts()], | ||||
| }]; | ||||
|  | ||||
| const assistantProcessConfig = { | ||||
|   input: './src/assistant-process.ts', | ||||
|   output: { | ||||
|     file: 'dist/assistant-process.mjs', | ||||
|     format: 'esm', | ||||
|   }, | ||||
|   plugins: [ | ||||
|     alias({ | ||||
|       entries: [{ find: '@', replacement: path.resolve('src') }], | ||||
|     }), | ||||
|     resolve({ | ||||
|       preferBuiltins: true, // 强制优先使用内置模块 | ||||
|     }), | ||||
|     commonjs(), | ||||
|     esbuild({ | ||||
|       target: 'node22', // | ||||
|     }), | ||||
|     json(), | ||||
|   ], | ||||
| }; | ||||
| const assistantProcessDtsConfig = [{   | ||||
|   input: './src/assistant-process.ts', | ||||
|   output: { | ||||
|     file: 'dist/assistant-process.d.ts', | ||||
|     format: 'esm', | ||||
|   }, | ||||
|   plugins: [dts()], | ||||
| }]; | ||||
|  | ||||
|  | ||||
|  | ||||
| export default [config, ...dtsConfig, moduleConfig, ...moduleDtsConfig, assistantConfigConfig, ...assistantConfigDtsConfig, assistantProcessConfig, ...assistantProcessDtsConfig]; | ||||
							
								
								
									
										1
									
								
								assistant-module/src/assistant-config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assistant-module/src/assistant-config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| export * from './config/index.ts'; | ||||
							
								
								
									
										1
									
								
								assistant-module/src/assistant-process.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assistant-module/src/assistant-process.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| export * from './process/index.ts'; | ||||
							
								
								
									
										1
									
								
								assistant-module/src/assistant-proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assistant-module/src/assistant-proxy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| export * from './proxy/index.ts'; | ||||
							
								
								
									
										111
									
								
								assistant-module/src/config/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								assistant-module/src/config/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| import path from 'path'; | ||||
| import { homedir } from 'os'; | ||||
| import fs from 'fs'; | ||||
| import { checkFileExists, createDir } from '../file/index.ts'; | ||||
| import { ProxyInfo } from '../proxy/proxy.ts'; | ||||
|  | ||||
| export const kevisualUrl = 'https://kevisual.xiongxiao.me'; | ||||
| const configDir = createDir(path.join(homedir(), '.config/envision')); | ||||
| export const configPath = path.join(configDir, 'assistant-config.json'); | ||||
| export const appConfigPath = path.join(configDir, 'assistant-app-config.json'); | ||||
| export const appDir = createDir(path.join(configDir, 'assistant-app/frontend')); | ||||
| export const appPidPath = path.join(configDir, 'assistant-app.pid'); | ||||
| export const LocalElectronAppUrl = 'https://assistant.app/user/tiptap/'; | ||||
|  | ||||
| type AssistantConfig = { | ||||
|   pageApi?: string; // https://kevisual.silkyai.cn | ||||
|   loadURL?: string; // https://assistant.app/user/tiptap/ | ||||
|   proxy?: { user: string; key: string; path: string }[]; | ||||
|   apiProxyList?: ProxyInfo[]; | ||||
| }; | ||||
| let assistantConfig: AssistantConfig; | ||||
| export const getConfig = () => { | ||||
|   try { | ||||
|     if (!checkFileExists(configPath)) { | ||||
|       fs.writeFileSync(configPath, JSON.stringify({ proxy: [] }, null, 2)); | ||||
|       return { | ||||
|         loadURL: LocalElectronAppUrl, | ||||
|         pageApi: '', | ||||
|         proxy: [], | ||||
|       }; | ||||
|     } | ||||
|     assistantConfig = JSON.parse(fs.readFileSync(configPath, 'utf8')); | ||||
|     return assistantConfig; | ||||
|   } catch (error) { | ||||
|     console.error(error); | ||||
|     return { | ||||
|       loadURL: LocalElectronAppUrl, | ||||
|       pageApi: '', | ||||
|       proxy: [], | ||||
|     }; | ||||
|   } | ||||
| }; | ||||
| export const getCacheAssistantConfig = () => { | ||||
|   if (assistantConfig) { | ||||
|     return assistantConfig; | ||||
|   } | ||||
|   return getConfig(); | ||||
| }; | ||||
|  | ||||
| export const setConfig = (config?: AssistantConfig) => { | ||||
|   if (!config) { | ||||
|     return assistantConfig; | ||||
|   } | ||||
|   assistantConfig = config; | ||||
|   fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); | ||||
|   return assistantConfig; | ||||
| }; | ||||
| type AppConfig = { | ||||
|   list: any[]; | ||||
| }; | ||||
| /** | ||||
|  * 应用配置 | ||||
|  * @returns | ||||
|  */ | ||||
| export const getAppConfig = (): AppConfig => { | ||||
|   if (!checkFileExists(appConfigPath)) { | ||||
|     return { | ||||
|       list: [], | ||||
|     }; | ||||
|   } | ||||
|   return JSON.parse(fs.readFileSync(appConfigPath, 'utf8')); | ||||
| }; | ||||
|  | ||||
| export const setAppConfig = (config: AppConfig) => { | ||||
|   fs.writeFileSync(appConfigPath, JSON.stringify(config, null, 2)); | ||||
|   return config; | ||||
| }; | ||||
|  | ||||
| export const addAppConfig = (app: any) => { | ||||
|   const config = getAppConfig(); | ||||
|   const assistantConfig = getCacheAssistantConfig(); | ||||
|   const _apps = config.list; | ||||
|   const _proxy = assistantConfig.proxy || []; | ||||
|   const { user, key } = app; | ||||
|   const newProxyInfo = { | ||||
|     user, | ||||
|     key, | ||||
|     path: `/${user}/${key}`, | ||||
|   }; | ||||
|   const _proxyIndex = _proxy.findIndex((_proxy: any) => _proxy.path === newProxyInfo.path); | ||||
|   if (_proxyIndex !== -1) { | ||||
|     _proxy[_proxyIndex] = newProxyInfo; | ||||
|   } else { | ||||
|     _proxy.push(newProxyInfo); | ||||
|   } | ||||
|  | ||||
|   const _app = _apps.findIndex((_app: any) => _app.id === app.id); | ||||
|   if (_app !== -1) { | ||||
|     _apps[_app] = app; | ||||
|   } else { | ||||
|     _apps.push(app); | ||||
|   } | ||||
|   setAppConfig({ ...config, list: _apps }); | ||||
|   setConfig({ ...assistantConfig, proxy: _proxy }); | ||||
|   return config; | ||||
| }; | ||||
|  | ||||
| export const getAppList = () => { | ||||
|   const config = getAppConfig(); | ||||
|   return config.list || []; | ||||
| }; | ||||
							
								
								
									
										20
									
								
								assistant-module/src/file/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								assistant-module/src/file/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| import fs from 'fs'; | ||||
|  | ||||
| export const checkFileExists = (filePath: string, checkIsFile = false) => { | ||||
|   try { | ||||
|     fs.accessSync(filePath); | ||||
|     if (checkIsFile) { | ||||
|       return fs.statSync(filePath).isFile(); | ||||
|     } | ||||
|     return true; | ||||
|   } catch (error) { | ||||
|     return false; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export const createDir = (dirPath: string) => { | ||||
|   if (!checkFileExists(dirPath)) { | ||||
|     fs.mkdirSync(dirPath, { recursive: true }); | ||||
|   } | ||||
|   return dirPath; | ||||
| }; | ||||
							
								
								
									
										2
									
								
								assistant-module/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								assistant-module/src/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| export * from './install/index.ts'; | ||||
| export * from './config/index.ts'; | ||||
							
								
								
									
										127
									
								
								assistant-module/src/install/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								assistant-module/src/install/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | ||||
| import path from 'path'; | ||||
| import fs from 'fs'; | ||||
|  | ||||
| type DownloadTask = { | ||||
|   downloadPath: string; | ||||
|   downloadUrl: string; | ||||
|   user: string; | ||||
|   key: string; | ||||
|   version: string; | ||||
| }; | ||||
| export type Package = { | ||||
|   id: string; | ||||
|   name?: string; | ||||
|   version?: string; | ||||
|   description?: string; | ||||
|   title?: string; | ||||
|   user?: string; | ||||
|   key?: string; | ||||
|   [key: string]: any; | ||||
| }; | ||||
| type InstallAppOpts = { | ||||
|   appDir?: string; | ||||
|   kevisualUrl?: string; | ||||
|   /** | ||||
|    * 是否是客户端, 下载到 assistant-config的下面 | ||||
|    */ | ||||
| }; | ||||
| export const installApp = async (app: Package, opts: InstallAppOpts = {}) => { | ||||
|   // const _app = demoData; | ||||
|   const { appDir = '', kevisualUrl = 'https://kevisual.cn' } = opts; | ||||
|   const _app = app; | ||||
|   try { | ||||
|     let files = _app.data.files || []; | ||||
|     const version = _app.version; | ||||
|     const user = _app.user; | ||||
|     const key = _app.key; | ||||
|  | ||||
|     const downFiles = files.map((file: any) => { | ||||
|       const noVersionPath = file.path.replace(`/${version}`, ''); | ||||
|       return { | ||||
|         ...file, | ||||
|         downloadPath: path.join(appDir, noVersionPath), | ||||
|         downloadUrl: `${kevisualUrl}/${noVersionPath}`, | ||||
|       }; | ||||
|     }); | ||||
|     const downloadTasks: DownloadTask[] = downFiles as any; | ||||
|     for (const file of downloadTasks) { | ||||
|       const downloadPath = file.downloadPath; | ||||
|       const downloadUrl = file.downloadUrl; | ||||
|       const dir = path.dirname(downloadPath); | ||||
|       if (!fs.existsSync(dir)) { | ||||
|         fs.mkdirSync(dir, { recursive: true }); | ||||
|       } | ||||
|       const res = await fetch(downloadUrl); | ||||
|       const blob = await res.blob(); | ||||
|       fs.writeFileSync(downloadPath, Buffer.from(await blob.arrayBuffer())); | ||||
|     } | ||||
|     let indexHtml = files.find((file: any) => file.name === 'index.html'); | ||||
|     if (!indexHtml) { | ||||
|       files.push({ | ||||
|         name: 'index.html', | ||||
|         path: `${user}/${key}/index.html`, | ||||
|       }); | ||||
|       fs.writeFileSync(path.join(appDir, `${user}/${key}/index.html`), JSON.stringify(app, null, 2)); | ||||
|     } | ||||
|     _app.data.files = files; | ||||
|     return { | ||||
|       code: 200, | ||||
|       data: _app, | ||||
|       message: 'Install app success', | ||||
|     }; | ||||
|   } catch (error) { | ||||
|     console.error(error); | ||||
|     return { | ||||
|       code: 500, | ||||
|       message: 'Install app failed', | ||||
|     }; | ||||
|   } | ||||
| }; | ||||
| export const checkAppDir = (appDir: string) => { | ||||
|   const files = fs.readdirSync(appDir); | ||||
|   if (files.length === 0) { | ||||
|     fs.rmSync(appDir, { recursive: true }); | ||||
|   } | ||||
| }; | ||||
| export const checkFileExists = (path: string) => { | ||||
|   try { | ||||
|     fs.accessSync(path); | ||||
|     return true; | ||||
|   } catch (error) { | ||||
|     return false; | ||||
|   } | ||||
| }; | ||||
| type UninstallAppOpts = { | ||||
|   appDir?: string; | ||||
| }; | ||||
| export const uninstallApp = async (app: Partial<Package>, opts: UninstallAppOpts = {}) => { | ||||
|   const { appDir = '' } = opts; | ||||
|   try { | ||||
|     const { user, key } = app; | ||||
|     const keyDir = path.join(appDir, user, key); | ||||
|     const parentDir = path.join(appDir, user); | ||||
|     if (!checkFileExists(appDir) || !checkFileExists(keyDir)) { | ||||
|       return { | ||||
|         code: 200, | ||||
|         message: 'uninstall app success', | ||||
|       }; | ||||
|     } | ||||
|     try { | ||||
|       // 删除appDir和文件 | ||||
|       fs.rmSync(keyDir, { recursive: true }); | ||||
|     } catch (error) { | ||||
|       console.error(error); | ||||
|     } | ||||
|     checkAppDir(parentDir); | ||||
|     return { | ||||
|       code: 200, | ||||
|       message: 'Uninstall app success', | ||||
|     }; | ||||
|   } catch (error) { | ||||
|     console.error(error); | ||||
|     return { | ||||
|       code: 500, | ||||
|       message: 'Uninstall app failed', | ||||
|     }; | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										70
									
								
								assistant-module/src/process/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								assistant-module/src/process/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| import { ChildProcess, fork } from 'child_process'; | ||||
|  | ||||
| export const runProcess = (appPath: string) => { | ||||
|   const process = fork(appPath); | ||||
|   process.on('exit', (code) => { | ||||
|     console.log(`Process exited with code ${code}`); | ||||
|   }); | ||||
|  | ||||
|   process.on('message', (message) => { | ||||
|     console.log('Message from child:', message); | ||||
|   }); | ||||
|  | ||||
|   // Example of sending a message to the child process | ||||
|   // process.send({ hello: 'world' }); | ||||
| }; | ||||
| class BaseProcess { | ||||
|   private process: ChildProcess; | ||||
|   status: 'running' | 'stopped' | 'error' = 'stopped'; | ||||
|   appPath: string; | ||||
|   constructor(appPath: string) { | ||||
|     this.appPath = appPath; | ||||
|     // this.createProcess(appPath); | ||||
|   } | ||||
|   createProcess(appPath: string = this.appPath) { | ||||
|     if (this.process) { | ||||
|       this.process.kill(); | ||||
|     } | ||||
|     this.appPath = appPath; | ||||
|     this.process = fork(appPath); | ||||
|     return this; | ||||
|   } | ||||
|   kill(signal?: NodeJS.Signals | number) { | ||||
|     if (this.process) { | ||||
|       this.process.kill(signal); | ||||
|     } | ||||
|     return this; | ||||
|   } | ||||
|   public send(message: any) { | ||||
|     this.process.send(message); | ||||
|   } | ||||
|  | ||||
|   public on(event: string, callback: (message: any) => void) { | ||||
|     this.process.on(event, callback); | ||||
|   } | ||||
|  | ||||
|   public onExit(callback: (code: number) => void) { | ||||
|     this.process.on('exit', callback); | ||||
|   } | ||||
|  | ||||
|   public onError(callback: (error: Error) => void) { | ||||
|     this.process.on('error', callback); | ||||
|   } | ||||
|  | ||||
|   public onMessage(callback: (message: any) => void) { | ||||
|     this.process.on('message', callback); | ||||
|   } | ||||
|  | ||||
|   public onClose(callback: () => void) { | ||||
|     this.process.on('close', callback); | ||||
|   } | ||||
|  | ||||
|   public onDisconnect(callback: () => void) { | ||||
|     this.process.on('disconnect', callback); | ||||
|   } | ||||
| } | ||||
| export class AssistantProcess extends BaseProcess { | ||||
|   constructor(appPath: string) { | ||||
|     super(appPath); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										82
									
								
								assistant-module/src/proxy/api-proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								assistant-module/src/proxy/api-proxy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| import http from 'http'; | ||||
| import https from 'https'; | ||||
|  | ||||
| import { ProxyInfo } from './proxy.ts'; | ||||
| export const defaultApiProxy = [ | ||||
|   { | ||||
|     path: '/api/router', | ||||
|     target: 'https://kevisual.xiongxiao.me', | ||||
|   }, | ||||
|   { | ||||
|     path: '/v1', | ||||
|     target: 'https://kevisual.xiongxiao.me', | ||||
|   }, | ||||
| ]; | ||||
| /** | ||||
|  * 创建api代理 | ||||
|  * @param api  | ||||
|  * @param paths ['/api/router', '/v1' ] | ||||
|  * @returns  | ||||
|  */ | ||||
| export const createApiProxy = (api: string, paths: string[] = ['/api/router', '/v1']) => { | ||||
|   const pathList = paths.map((item) => { | ||||
|     return { | ||||
|       path: item, | ||||
|       target: new URL(api).origin, | ||||
|     }; | ||||
|   }); | ||||
|   return pathList; | ||||
| }; | ||||
|  | ||||
| export const apiProxy = (req: http.IncomingMessage, res: http.ServerResponse, proxyApi: ProxyInfo) => { | ||||
|   const _u = new URL(req.url, `${proxyApi.target}`); | ||||
|   console.log('proxyApi', req.url, _u.href); | ||||
|   // 设置代理请求的目标 URL 和请求头 | ||||
|   let header: any = {}; | ||||
|   if (req.headers?.['Authorization'] && !req.headers?.['authorization']) { | ||||
|     header.authorization = req.headers['Authorization']; | ||||
|   } | ||||
|   // 提取req的headers中的非HOST的header | ||||
|   const headers = Object.keys(req.headers).filter((item) => item && item.toLowerCase() !== 'host'); | ||||
|   headers.forEach((item) => { | ||||
|     if (item.toLowerCase() === 'origin') { | ||||
|       header.origin = new URL(proxyApi.target).origin; | ||||
|       return; | ||||
|     } | ||||
|     if (item.toLowerCase() === 'referer') { | ||||
|       header.referer = new URL(req.url, proxyApi.target).href; | ||||
|       return; | ||||
|     } | ||||
|     header[item] = req.headers[item]; | ||||
|   }); | ||||
|   const options = { | ||||
|     host: _u.hostname, | ||||
|     path: req.url, | ||||
|     method: req.method, | ||||
|     headers: { | ||||
|       ...header, | ||||
|     }, | ||||
|   }; | ||||
|   console.log('options', JSON.stringify(options, null, 2)); | ||||
|   if (_u.port) { | ||||
|     // @ts-ignore | ||||
|     options.port = _u.port; | ||||
|   } | ||||
|   const httpProxy = _u.protocol === 'https:' ? https : http; | ||||
|   // 创建代理请求 | ||||
|   const proxyReq = httpProxy.request(options, (proxyRes) => { | ||||
|     // 将代理服务器的响应头和状态码返回给客户端 | ||||
|     res.writeHead(proxyRes.statusCode, proxyRes.headers); | ||||
|     // 将代理响应流写入客户端响应 | ||||
|     proxyRes.pipe(res, { end: true }); | ||||
|   }); | ||||
|   // 处理代理请求的错误事件 | ||||
|   proxyReq.on('error', (err) => { | ||||
|     console.error(`Proxy request error: ${err.message}`); | ||||
|     res.writeHead(500, { 'Content-Type': 'text/plain' }); | ||||
|     res.write(`Proxy request error: ${err.message}`); | ||||
|   }); | ||||
|   // 处理 POST 请求的请求体(传递数据到目标服务器),end:true 表示当请求体结束时,关闭请求 | ||||
|   req.pipe(proxyReq, { end: true }); | ||||
|   return; | ||||
| }; | ||||
							
								
								
									
										47
									
								
								assistant-module/src/proxy/file-proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								assistant-module/src/proxy/file-proxy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| import http from 'http'; | ||||
| import send from 'send'; | ||||
| import fs from 'fs'; | ||||
| import { fileIsExist } from '@kevisual/use-config'; | ||||
| import path from 'path'; | ||||
| import { ProxyInfo } from './proxy.ts'; | ||||
|  | ||||
| export const fileProxy = (req: http.IncomingMessage, res: http.ServerResponse, proxyApi: ProxyInfo) => { | ||||
|   // url开头的文件 | ||||
|   const url = new URL(req.url, 'http://localhost'); | ||||
|   let pathname = url.pathname.slice(1); | ||||
|   const { indexPath = '', target = '', rootPath = process.cwd() } = proxyApi; | ||||
|   try { | ||||
|     if (pathname.endsWith('/')) { | ||||
|       pathname = pathname + 'index.html'; | ||||
|     } | ||||
|     // 检测文件是否存在,如果文件不存在,则返回404 | ||||
|     let filePath = path.join(rootPath, target, pathname); | ||||
|     let exist = fileIsExist(filePath); | ||||
|     if (!exist) { | ||||
|       filePath = path.join(rootPath, target, '/' + indexPath); | ||||
|       exist = fileIsExist(filePath); | ||||
|     } | ||||
|     console.log('filePath', filePath, exist); | ||||
|      | ||||
|     if (!exist) { | ||||
|       res.statusCode = 404; | ||||
|       res.end('Not Found File'); | ||||
|       return; | ||||
|     } | ||||
|     const ext = path.extname(filePath); | ||||
|     let maxAge = 24 * 60 * 60 * 1000; // 24小时 | ||||
|     if (ext === '.html') { | ||||
|       maxAge = 0; | ||||
|     } | ||||
|     let sendFilePath = filePath.replace(rootPath + '/', ''); | ||||
|     const file = send(req, sendFilePath, { | ||||
|       root: rootPath, | ||||
|       maxAge, | ||||
|     }); | ||||
|     file.pipe(res); | ||||
|   } catch (error) { | ||||
|     res.statusCode = 404; | ||||
|     res.end('Error:Not Found File'); | ||||
|     return; | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										5
									
								
								assistant-module/src/proxy/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								assistant-module/src/proxy/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| export * from './proxy.ts'; | ||||
| export * from './file-proxy.ts'; | ||||
| export { default as send } from 'send'; | ||||
| export * from './api-proxy.ts'; | ||||
| export * from './wx-proxy.ts'; | ||||
							
								
								
									
										35
									
								
								assistant-module/src/proxy/proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								assistant-module/src/proxy/proxy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| export type ProxyInfo = { | ||||
|   path?: string; | ||||
|   target?: string; | ||||
|   type?: 'static' | 'dynamic' | 'minio'; | ||||
|   /** | ||||
|    * 首要文件,比如index.html, 设置了首要文件,如果文件不存在,则访问首要文件 | ||||
|    */ | ||||
|   indexPath?: string; | ||||
|   /** | ||||
|    * 根路径, 默认是process.cwd() | ||||
|    */ | ||||
|   rootPath?: string; | ||||
| }; | ||||
| export type ApiList = { | ||||
|   path: string; | ||||
|   /** | ||||
|    * url或者相对路径 | ||||
|    */ | ||||
|   target: string; | ||||
|   /** | ||||
|    * 类型 | ||||
|    */ | ||||
|   type?: 'static' | 'dynamic' | 'minio'; | ||||
| }[]; | ||||
|  | ||||
| /** | ||||
|  | ||||
| [ | ||||
|   { | ||||
|     path: '/api/v1/user', | ||||
|     target: 'http://localhost:3000/api/v1/user', | ||||
|     type: 'dynamic', | ||||
|   }, | ||||
| ] | ||||
|  */ | ||||
							
								
								
									
										48
									
								
								assistant-module/src/proxy/wx-proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								assistant-module/src/proxy/wx-proxy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| import { Server } from 'http'; | ||||
| import WebSocket from 'ws'; | ||||
| /** | ||||
|  * websocket代理 | ||||
|  * apiList: [{ path: '/api/router', target: 'https://kevisual.xiongxiao.me' }] | ||||
|  * @param server | ||||
|  * @param config | ||||
|  */ | ||||
| export const wsProxy = (server: Server, config: { apiList: any[] }) => { | ||||
|   console.log('Upgrade initialization started'); | ||||
|  | ||||
|   server.on('upgrade', (req, socket, head) => { | ||||
|     const proxyApiList = config?.apiList || []; | ||||
|     const proxyApi = proxyApiList.find((item) => req.url.startsWith(item.path)); | ||||
|  | ||||
|     if (proxyApi) { | ||||
|       const _u = new URL(req.url, `${proxyApi.target}`); | ||||
|       const isHttps = _u.protocol === 'https:'; | ||||
|       const wsProtocol = isHttps ? 'wss' : 'ws'; | ||||
|       const wsUrl = `${wsProtocol}://${_u.hostname}${_u.pathname}`; | ||||
|  | ||||
|       const proxySocket = new WebSocket(wsUrl, { | ||||
|         headers: req.headers, | ||||
|       }); | ||||
|  | ||||
|       proxySocket.on('open', () => { | ||||
|         socket.on('data', (data) => { | ||||
|           proxySocket.send(data); | ||||
|         }); | ||||
|  | ||||
|         proxySocket.on('message', (message) => { | ||||
|           socket.write(message); | ||||
|         }); | ||||
|       }); | ||||
|  | ||||
|       proxySocket.on('error', (err) => { | ||||
|         console.error(`WebSocket proxy error: ${err.message}`); | ||||
|         socket.end(); | ||||
|       }); | ||||
|  | ||||
|       socket.on('error', () => { | ||||
|         proxySocket.close(); | ||||
|       }); | ||||
|     } else { | ||||
|       socket.end(); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
							
								
								
									
										33
									
								
								assistant-module/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								assistant-module/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| { | ||||
|   "compilerOptions": { | ||||
|     "module": "nodenext", | ||||
|     "target": "esnext", | ||||
|     "noImplicitAny": false, | ||||
|     "outDir": "./dist", | ||||
|     "sourceMap": false, | ||||
|     "allowJs": true, | ||||
|     "newLine": "LF", | ||||
|     "baseUrl": "./", | ||||
|     "typeRoots": [ | ||||
|       "node_modules/@types", | ||||
|       "node_modules/@kevisual/types" | ||||
|     ], | ||||
|     "declaration": true, | ||||
|     "noEmit": false, | ||||
|     "allowImportingTsExtensions": true, | ||||
|     "emitDeclarationOnly": true, | ||||
|     "moduleResolution": "NodeNext", | ||||
|     "experimentalDecorators": true, | ||||
|     "emitDecoratorMetadata": true, | ||||
|     "esModuleInterop": true, | ||||
|     "paths": { | ||||
|       "@/*": [ | ||||
|         "src/*" | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|   "include": [ | ||||
|     "src/**/*.ts", | ||||
|   ], | ||||
|   "exclude": [], | ||||
| } | ||||
							
								
								
									
										23
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,19 +1,21 @@ | ||||
| { | ||||
|   "name": "demo-app", | ||||
|   "name": "assistant-center", | ||||
|   "version": "0.0.1", | ||||
|   "description": "", | ||||
|   "main": "index.js", | ||||
|   "app": { | ||||
|     "key": "demo-app", | ||||
|     "key": "assistant-center", | ||||
|     "entry": "dist/app.mjs", | ||||
|     "type": "system-app", | ||||
|     "files": [ | ||||
|       "dist" | ||||
|       "dist", | ||||
|       "pem" | ||||
|     ] | ||||
|   }, | ||||
|   "scripts": { | ||||
|     "watch": "rollup -c rollup.config.mjs -w", | ||||
|     "dev": "cross-env NODE_ENV=development nodemon --delay 2.5 -e js,cjs,mjs --exec node dist/app.mjs", | ||||
|     "build": "rollup -c rollup.config.mjs", | ||||
|     "test": "tsx  test/**/*.ts", | ||||
|     "dev:watch": "cross-env NODE_ENV=development concurrently -n \"Watch,Dev\" -c \"green,blue\" \"npm run watch\" \"sleep 1 && npm run dev\" ", | ||||
|     "clean": "rm -rf dist", | ||||
| @@ -31,20 +33,22 @@ | ||||
|     "src" | ||||
|   ], | ||||
|   "dependencies": { | ||||
|     "@kevisual/code-center-module": "0.0.11-alpha.1", | ||||
|     "@kevisual/mark": "0.0.6", | ||||
|     "@kevisual/router": "0.0.8-alpha.3", | ||||
|     "@kevisual/code-center-module": "0.0.13", | ||||
|     "@kevisual/mark": "0.0.7", | ||||
|     "@kevisual/router": "0.0.9", | ||||
|     "cookie": "^1.0.2", | ||||
|     "dayjs": "^1.11.13", | ||||
|     "formidable": "^3.5.2", | ||||
|     "json5": "^2.2.3", | ||||
|     "lodash-es": "^4.17.21" | ||||
|     "lodash-es": "^4.17.21", | ||||
|     "ws": "^8.18.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@kevisual/assistant-module": "workspace:*", | ||||
|     "@kevisual/types": "^0.0.6", | ||||
|     "@kevisual/use-config": "^1.0.9", | ||||
|     "@rollup/plugin-alias": "^5.1.1", | ||||
|     "@rollup/plugin-commonjs": "^28.0.2", | ||||
|     "@rollup/plugin-commonjs": "^28.0.3", | ||||
|     "@rollup/plugin-json": "^6.1.0", | ||||
|     "@rollup/plugin-node-resolve": "^16.0.0", | ||||
|     "@rollup/plugin-replace": "^6.0.2", | ||||
| @@ -52,7 +56,8 @@ | ||||
|     "@types/crypto-js": "^4.2.2", | ||||
|     "@types/formidable": "^3.4.5", | ||||
|     "@types/lodash-es": "^4.17.12", | ||||
|     "@types/node": "^22.13.8", | ||||
|     "@types/node": "^22.13.9", | ||||
|     "@types/ws": "^8.18.0", | ||||
|     "concurrently": "^9.1.2", | ||||
|     "cross-env": "^7.0.3", | ||||
|     "nodemon": "^3.1.9", | ||||
|   | ||||
							
								
								
									
										15
									
								
								pem/https-cert.pem
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								pem/https-cert.pem
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| -----BEGIN CERTIFICATE----- | ||||
| MIICXTCCAcagAwIBAgIJHsP036vqWER/MA0GCSqGSIb3DQEBBQUAMF8xCjAIBgNV | ||||
| BAMTASoxCzAJBgNVBAYTAkNOMREwDwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMI | ||||
| SGFuZ3pob3UxETAPBgNVBAoTCEVudmlzaW9uMQswCQYDVQQLEwJJVDAeFw0yNTAz | ||||
| MDcxNDIwMTJaFw0yNjAzMDcxNDIwMTJaMF8xCjAIBgNVBAMTASoxCzAJBgNVBAYT | ||||
| AkNOMREwDwYDVQQIEwhaaGVKaWFuZzERMA8GA1UEBxMISGFuZ3pob3UxETAPBgNV | ||||
| BAoTCEVudmlzaW9uMQswCQYDVQQLEwJJVDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw | ||||
| gYkCgYEAquA2XnwduVSJHvnTW4r5yodz/joTPUi+r8kS/KJyR/NQ5xovtDY2gJoO | ||||
| nJk8qekcLKuofskIIu4HFsCE7AYBkQGaYmc+0cCQCmEpwivesbeMB0ydz+6NwLQn | ||||
| 32HVjtMtx3gUcywGdMntiQb/P9FIhtE132wOmW9PeSl0dx/nyrUCAwEAAaMhMB8w | ||||
| HQYDVR0RBBYwFIIBKoIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBBQUAA4GB | ||||
| AJsjIZgb6iE4OTXoEDiBPmHM+byWs20K2eCvi79V9/vns90IroBQfGirIsovv923 | ||||
| SqjmdAFsZkRUbZvX99lBX0mmZK9KTE4K9YUm7bv+d8+fBPxAgNFSTRiSNBeNh0Lh | ||||
| HdJUiI/tzIfI6RRg1pFDC1tOG083Cl/YElN879w3Iipi | ||||
| -----END CERTIFICATE----- | ||||
							
								
								
									
										15
									
								
								pem/https-key.pem
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								pem/https-key.pem
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| -----BEGIN RSA PRIVATE KEY----- | ||||
| MIICXAIBAAKBgQCq4DZefB25VIke+dNbivnKh3P+OhM9SL6vyRL8onJH81DnGi+0 | ||||
| NjaAmg6cmTyp6Rwsq6h+yQgi7gcWwITsBgGRAZpiZz7RwJAKYSnCK96xt4wHTJ3P | ||||
| 7o3AtCffYdWO0y3HeBRzLAZ0ye2JBv8/0UiG0TXfbA6Zb095KXR3H+fKtQIDAQAB | ||||
| AoGADDEbL/qjFEoXzoH8tpdf4zdu60CxhrneASTTmfrtNH0D1LlllfIYSWy0hi/Y | ||||
| yDa9r+I/j2xAjF13XAQ4d66mBdjCRATLx/aL495o+e6NkIBEAgdP88hHm13F6gg+ | ||||
| h8iMixs5mkwU41sghnCYeBqlziKPi8fsoTmhK0VETFUtDQECQQDT0kZ7OCEVNcz0 | ||||
| LAUPO7ukeHAYnGYns+Q3F3kgonzHPGflClH5dsg0NS1HFQj6Ny2oyUupjNePOCJK | ||||
| 88zNehIlAkEAzoO9zrE+AoTPleVpe7TAUlZB1YMa7W1C5owjyEkv4TjIe8mpwWM/ | ||||
| 9vVe+SGUnc6DZy6xkk5zWmA2w18SexXJUQJBAJQbcyy1EmzCMYyJOwBrw8g8biTH | ||||
| NqaMIgZjY05uTtEAa6S6kpbbdyEKDZ6mFqDd9A8QsNbco9yAY3oE/i6uLAECQHOt | ||||
| a9aphZiXmEfYl3uJxejZFEtrAtxXxY+qlCiOhllcG0Drt0DyPVQyIZ7fZoX2tbhI | ||||
| eYMAmrDXEBXj3VBA5eECQCLGpQKqo06QwP2qZ9mEaPB9KvVcABo97b9Lf7VUqcJx | ||||
| tFWRSlpeICpDQZHqX92nwoD/2fGCH3br3o94k1oyApI= | ||||
| -----END RSA PRIVATE KEY----- | ||||
							
								
								
									
										240
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										240
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @@ -9,14 +9,14 @@ importers: | ||||
|   .: | ||||
|     dependencies: | ||||
|       '@kevisual/code-center-module': | ||||
|         specifier: 0.0.11-alpha.1 | ||||
|         version: 0.0.11-alpha.1(@kevisual/auth@1.0.5)(@kevisual/router@0.0.8-alpha.3)(@kevisual/use-config@1.0.9)(ioredis@5.5.0)(pg@8.13.3)(sequelize@6.37.5(pg@8.13.3)) | ||||
|         specifier: 0.0.13 | ||||
|         version: 0.0.13(@kevisual/auth@1.0.5)(@kevisual/router@0.0.9)(@kevisual/use-config@1.0.9)(ioredis@5.5.0)(pg@8.13.3)(sequelize@6.37.5(pg@8.13.3)) | ||||
|       '@kevisual/mark': | ||||
|         specifier: 0.0.6 | ||||
|         version: 0.0.6(esbuild@0.25.0) | ||||
|         specifier: 0.0.7 | ||||
|         version: 0.0.7(esbuild@0.25.0) | ||||
|       '@kevisual/router': | ||||
|         specifier: 0.0.8-alpha.3 | ||||
|         version: 0.0.8-alpha.3 | ||||
|         specifier: 0.0.9 | ||||
|         version: 0.0.9 | ||||
|       cookie: | ||||
|         specifier: ^1.0.2 | ||||
|         version: 1.0.2 | ||||
| @@ -32,7 +32,13 @@ importers: | ||||
|       lodash-es: | ||||
|         specifier: ^4.17.21 | ||||
|         version: 4.17.21 | ||||
|       ws: | ||||
|         specifier: ^8.18.1 | ||||
|         version: 8.18.1 | ||||
|     devDependencies: | ||||
|       '@kevisual/assistant-module': | ||||
|         specifier: workspace:* | ||||
|         version: link:assistant-module | ||||
|       '@kevisual/types': | ||||
|         specifier: ^0.0.6 | ||||
|         version: 0.0.6 | ||||
| @@ -43,8 +49,8 @@ importers: | ||||
|         specifier: ^5.1.1 | ||||
|         version: 5.1.1(rollup@4.34.9) | ||||
|       '@rollup/plugin-commonjs': | ||||
|         specifier: ^28.0.2 | ||||
|         version: 28.0.2(rollup@4.34.9) | ||||
|         specifier: ^28.0.3 | ||||
|         version: 28.0.3(rollup@4.34.9) | ||||
|       '@rollup/plugin-json': | ||||
|         specifier: ^6.1.0 | ||||
|         version: 6.1.0(rollup@4.34.9) | ||||
| @@ -67,8 +73,11 @@ importers: | ||||
|         specifier: ^4.17.12 | ||||
|         version: 4.17.12 | ||||
|       '@types/node': | ||||
|         specifier: ^22.13.8 | ||||
|         version: 22.13.8 | ||||
|         specifier: ^22.13.9 | ||||
|         version: 22.13.9 | ||||
|       '@types/ws': | ||||
|         specifier: ^8.18.0 | ||||
|         version: 8.18.0 | ||||
|       concurrently: | ||||
|         specifier: ^9.1.2 | ||||
|         version: 9.1.2 | ||||
| @@ -106,6 +115,25 @@ importers: | ||||
|         specifier: ^5.8.2 | ||||
|         version: 5.8.2 | ||||
|  | ||||
|   assistant-module: | ||||
|     dependencies: | ||||
|       send: | ||||
|         specifier: ^1.1.0 | ||||
|         version: 1.1.0 | ||||
|       ws: | ||||
|         specifier: ^8.18.1 | ||||
|         version: 8.18.1 | ||||
|     devDependencies: | ||||
|       '@types/node': | ||||
|         specifier: ^22.13.10 | ||||
|         version: 22.13.10 | ||||
|       '@types/send': | ||||
|         specifier: ^0.17.4 | ||||
|         version: 0.17.4 | ||||
|       '@types/ws': | ||||
|         specifier: ^8.18.0 | ||||
|         version: 8.18.0 | ||||
|  | ||||
| packages: | ||||
|  | ||||
|   '@babel/code-frame@7.26.2': | ||||
| @@ -279,8 +307,8 @@ packages: | ||||
|   '@kevisual/auth@1.0.5': | ||||
|     resolution: {integrity: sha512-GwsLj7unKXi7lmMiIIgdig4LwwLiDJnOy15HHZR5gMbyK6s5/uJiMY5RXPB2+onGzTNDqFo/hXjsD2wkerHPVg==} | ||||
|  | ||||
|   '@kevisual/code-center-module@0.0.11-alpha.1': | ||||
|     resolution: {integrity: sha512-0HPSZw4PmhejE7p4cBIe174/h434XE3dgrwHoRZLYZSZyJ/aaBfR+3RybdvDN5dnyusLkPdgRq+Qern53Lqp1A==} | ||||
|   '@kevisual/code-center-module@0.0.13': | ||||
|     resolution: {integrity: sha512-A82sX8rdG2igyVLIF+0dagcUsGfk2b0JAga1BDDr9mrChrG1HbG1uYN7JJdjJbGE6zGYqGxRZwxKZmzB/+KMnw==} | ||||
|     peerDependencies: | ||||
|       '@kevisual/auth': ^1.0.5 | ||||
|       '@kevisual/router': ^0.0.7 | ||||
| @@ -292,8 +320,8 @@ packages: | ||||
|   '@kevisual/load@0.0.4': | ||||
|     resolution: {integrity: sha512-TJBieKsEoEPfP4+tDyhNZdMX2LMAGiDZ/IrAXPFWB4jeFP0Ywm1W5xDV52LhhHq4nwTmuhyTVmPxJYiEVYTHtA==} | ||||
|  | ||||
|   '@kevisual/mark@0.0.6': | ||||
|     resolution: {integrity: sha512-QhJXeJbeQIbouitqE3s67G92tkx44XoC4dDZUXCd28xGJyeCegkkQ6n4uxKPLBCh3XhDtek1e2EZjhK97wyZJA==} | ||||
|   '@kevisual/mark@0.0.7': | ||||
|     resolution: {integrity: sha512-PiEEy4yvWEpixw76PzgrIWeNelzm+FrhtzFmqJU92o5GkgawaFwighcvIxqcVZRKeEFF4uvlTjFrGeQvXw6F4A==} | ||||
|  | ||||
|   '@kevisual/rollup-tools@0.0.1': | ||||
|     resolution: {integrity: sha512-TdCN+IU0fyHudiiqYvobXQ8r5MltfM/cKmSS59iopyL8YYwXwcipOS4S24NWA79g7uwJfSUNk5lg3yVhom79fQ==} | ||||
| @@ -302,8 +330,8 @@ packages: | ||||
|   '@kevisual/router@0.0.7': | ||||
|     resolution: {integrity: sha512-4n1Tp4YLoraJv7jtfy7jbuLGyAj0B2QkTlnlEDHCUTlEUOvOkjtf7DHAe2SL92fTgXhSbod0I/0vUcDF85oj/w==} | ||||
|  | ||||
|   '@kevisual/router@0.0.8-alpha.3': | ||||
|     resolution: {integrity: sha512-iWFatFe0ggBTpSmCqtRIVbMq8YnekM2beIciWmoE9kIfadosdyKW/vWoK5wfTUu4nB4GORCiDO3YrAYnoCaQug==} | ||||
|   '@kevisual/router@0.0.9': | ||||
|     resolution: {integrity: sha512-qPyC2GVJ7iOIdJCCKNDsWMAKOQeSJW9HBpL5ZWKHTbi+t4jJBGTzIlXmjKeMHRd0lr/Qq1imQvlkSh4hlrbodA==} | ||||
|  | ||||
|   '@kevisual/types@0.0.6': | ||||
|     resolution: {integrity: sha512-7yxe1QmuC5g7lI/1Hm+zXly8if0z+ZqGM1SVOVv2VNRwRAVYBJDc365zWCCfRwE+5YaB2daWTe5zBOU4EkltkQ==} | ||||
| @@ -354,8 +382,8 @@ packages: | ||||
|       rollup: | ||||
|         optional: true | ||||
|  | ||||
|   '@rollup/plugin-commonjs@28.0.2': | ||||
|     resolution: {integrity: sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==} | ||||
|   '@rollup/plugin-commonjs@28.0.3': | ||||
|     resolution: {integrity: sha512-pyltgilam1QPdn+Zd9gaCfOLcnjMEJ9gV+bTw6/r73INdvzf1ah9zLIJBm+kW7R6IUFIQ1YO+VqZtYxZNWFPEQ==} | ||||
|     engines: {node: '>=16.0.0 || 14 >= 14.17'} | ||||
|     peerDependencies: | ||||
|       rollup: ^2.68.0||^3.0.0||^4.0.0 | ||||
| @@ -549,6 +577,9 @@ packages: | ||||
|   '@types/lodash@4.17.15': | ||||
|     resolution: {integrity: sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==} | ||||
|  | ||||
|   '@types/mime@1.3.5': | ||||
|     resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} | ||||
|  | ||||
|   '@types/minimatch@5.1.2': | ||||
|     resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} | ||||
|  | ||||
| @@ -558,15 +589,24 @@ packages: | ||||
|   '@types/node-forge@1.3.11': | ||||
|     resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} | ||||
|  | ||||
|   '@types/node@22.13.8': | ||||
|     resolution: {integrity: sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==} | ||||
|   '@types/node@22.13.10': | ||||
|     resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==} | ||||
|  | ||||
|   '@types/node@22.13.9': | ||||
|     resolution: {integrity: sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==} | ||||
|  | ||||
|   '@types/resolve@1.20.2': | ||||
|     resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} | ||||
|  | ||||
|   '@types/send@0.17.4': | ||||
|     resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} | ||||
|  | ||||
|   '@types/validator@13.12.2': | ||||
|     resolution: {integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==} | ||||
|  | ||||
|   '@types/ws@8.18.0': | ||||
|     resolution: {integrity: sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw==} | ||||
|  | ||||
|   accepts@1.3.8: | ||||
|     resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} | ||||
|     engines: {node: '>= 0.6'} | ||||
| @@ -854,6 +894,14 @@ packages: | ||||
|     resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} | ||||
|     engines: {node: '>=0.10'} | ||||
|  | ||||
|   depd@2.0.0: | ||||
|     resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} | ||||
|     engines: {node: '>= 0.8'} | ||||
|  | ||||
|   destroy@1.2.0: | ||||
|     resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} | ||||
|     engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} | ||||
|  | ||||
|   dezalgo@1.0.4: | ||||
|     resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} | ||||
|  | ||||
| @@ -875,12 +923,19 @@ packages: | ||||
|   eastasianwidth@0.2.0: | ||||
|     resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} | ||||
|  | ||||
|   ee-first@1.1.1: | ||||
|     resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} | ||||
|  | ||||
|   emoji-regex@8.0.0: | ||||
|     resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} | ||||
|  | ||||
|   emoji-regex@9.2.2: | ||||
|     resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} | ||||
|  | ||||
|   encodeurl@2.0.0: | ||||
|     resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} | ||||
|     engines: {node: '>= 0.8'} | ||||
|  | ||||
|   engine.io-parser@5.2.3: | ||||
|     resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} | ||||
|     engines: {node: '>=10.0.0'} | ||||
| @@ -932,6 +987,9 @@ packages: | ||||
|     resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} | ||||
|     engines: {node: '>=6'} | ||||
|  | ||||
|   escape-html@1.0.3: | ||||
|     resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} | ||||
|  | ||||
|   escape-string-regexp@4.0.0: | ||||
|     resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} | ||||
|     engines: {node: '>=10'} | ||||
| @@ -960,6 +1018,10 @@ packages: | ||||
|     resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} | ||||
|     engines: {node: '>=0.10.0'} | ||||
|  | ||||
|   etag@1.8.1: | ||||
|     resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} | ||||
|     engines: {node: '>= 0.6'} | ||||
|  | ||||
|   eventemitter2@0.4.14: | ||||
|     resolution: {integrity: sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==} | ||||
|  | ||||
| @@ -1020,6 +1082,10 @@ packages: | ||||
|   formidable@3.5.2: | ||||
|     resolution: {integrity: sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==} | ||||
|  | ||||
|   fresh@0.5.2: | ||||
|     resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} | ||||
|     engines: {node: '>= 0.6'} | ||||
|  | ||||
|   fs-extra@8.1.0: | ||||
|     resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} | ||||
|     engines: {node: '>=6 <7 || >=8'} | ||||
| @@ -1147,6 +1213,10 @@ packages: | ||||
|     resolution: {integrity: sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw==} | ||||
|     engines: {node: '>=8'} | ||||
|  | ||||
|   http-errors@2.0.0: | ||||
|     resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} | ||||
|     engines: {node: '>= 0.8'} | ||||
|  | ||||
|   http-proxy-agent@7.0.2: | ||||
|     resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} | ||||
|     engines: {node: '>= 14'} | ||||
| @@ -1491,6 +1561,10 @@ packages: | ||||
|     resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} | ||||
|     engines: {node: '>= 0.4'} | ||||
|  | ||||
|   on-finished@2.4.1: | ||||
|     resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} | ||||
|     engines: {node: '>= 0.8'} | ||||
|  | ||||
|   once@1.4.0: | ||||
|     resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} | ||||
|  | ||||
| @@ -1650,6 +1724,10 @@ packages: | ||||
|   queue-microtask@1.2.3: | ||||
|     resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} | ||||
|  | ||||
|   range-parser@1.2.1: | ||||
|     resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} | ||||
|     engines: {node: '>= 0.6'} | ||||
|  | ||||
|   read@1.0.7: | ||||
|     resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} | ||||
|     engines: {node: '>=0.8'} | ||||
| @@ -1780,6 +1858,10 @@ packages: | ||||
|     engines: {node: '>=10'} | ||||
|     hasBin: true | ||||
|  | ||||
|   send@1.1.0: | ||||
|     resolution: {integrity: sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==} | ||||
|     engines: {node: '>= 18'} | ||||
|  | ||||
|   sequelize-pool@7.1.0: | ||||
|     resolution: {integrity: sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==} | ||||
|     engines: {node: '>= 10.0.0'} | ||||
| @@ -1829,6 +1911,9 @@ packages: | ||||
|     resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} | ||||
|     engines: {node: '>= 0.4'} | ||||
|  | ||||
|   setprototypeof@1.2.0: | ||||
|     resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} | ||||
|  | ||||
|   shebang-command@2.0.0: | ||||
|     resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} | ||||
|     engines: {node: '>=8'} | ||||
| @@ -1922,6 +2007,10 @@ packages: | ||||
|   standard-as-callback@2.1.0: | ||||
|     resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} | ||||
|  | ||||
|   statuses@2.0.1: | ||||
|     resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} | ||||
|     engines: {node: '>= 0.8'} | ||||
|  | ||||
|   stop-iteration-iterator@1.1.0: | ||||
|     resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} | ||||
|     engines: {node: '>= 0.4'} | ||||
| @@ -1984,6 +2073,10 @@ packages: | ||||
|     resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} | ||||
|     engines: {node: '>=8.0'} | ||||
|  | ||||
|   toidentifier@1.0.1: | ||||
|     resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} | ||||
|     engines: {node: '>=0.6'} | ||||
|  | ||||
|   toposort-class@1.0.1: | ||||
|     resolution: {integrity: sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==} | ||||
|  | ||||
| @@ -2127,8 +2220,8 @@ packages: | ||||
|       utf-8-validate: | ||||
|         optional: true | ||||
|  | ||||
|   ws@8.18.0: | ||||
|     resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} | ||||
|   ws@8.18.1: | ||||
|     resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} | ||||
|     engines: {node: '>=10.0.0'} | ||||
|     peerDependencies: | ||||
|       bufferutil: ^4.0.1 | ||||
| @@ -2263,10 +2356,10 @@ snapshots: | ||||
|  | ||||
|   '@kevisual/auth@1.0.5': {} | ||||
|  | ||||
|   '@kevisual/code-center-module@0.0.11-alpha.1(@kevisual/auth@1.0.5)(@kevisual/router@0.0.8-alpha.3)(@kevisual/use-config@1.0.9)(ioredis@5.5.0)(pg@8.13.3)(sequelize@6.37.5(pg@8.13.3))': | ||||
|   '@kevisual/code-center-module@0.0.13(@kevisual/auth@1.0.5)(@kevisual/router@0.0.9)(@kevisual/use-config@1.0.9)(ioredis@5.5.0)(pg@8.13.3)(sequelize@6.37.5(pg@8.13.3))': | ||||
|     dependencies: | ||||
|       '@kevisual/auth': 1.0.5 | ||||
|       '@kevisual/router': 0.0.8-alpha.3 | ||||
|       '@kevisual/router': 0.0.9 | ||||
|       '@kevisual/use-config': 1.0.9 | ||||
|       ioredis: 5.5.0 | ||||
|       nanoid: 5.1.2 | ||||
| @@ -2283,13 +2376,14 @@ snapshots: | ||||
|     dependencies: | ||||
|       eventemitter3: 5.0.1 | ||||
|  | ||||
|   '@kevisual/mark@0.0.6(esbuild@0.25.0)': | ||||
|   '@kevisual/mark@0.0.7(esbuild@0.25.0)': | ||||
|     dependencies: | ||||
|       '@kevisual/auth': 1.0.5 | ||||
|       '@kevisual/rollup-tools': 0.0.1(esbuild@0.25.0) | ||||
|       '@kevisual/router': 0.0.7 | ||||
|       '@kevisual/use-config': 1.0.9 | ||||
|       cookie: 1.0.2 | ||||
|       nanoid: 5.1.2 | ||||
|       pg: 8.13.3 | ||||
|       sequelize: 6.37.5(pg@8.13.3) | ||||
|     transitivePeerDependencies: | ||||
| @@ -2310,12 +2404,12 @@ snapshots: | ||||
|   '@kevisual/rollup-tools@0.0.1(esbuild@0.25.0)': | ||||
|     dependencies: | ||||
|       '@rollup/plugin-alias': 5.1.1(rollup@4.34.9) | ||||
|       '@rollup/plugin-commonjs': 28.0.2(rollup@4.34.9) | ||||
|       '@rollup/plugin-commonjs': 28.0.3(rollup@4.34.9) | ||||
|       '@rollup/plugin-json': 6.1.0(rollup@4.34.9) | ||||
|       '@rollup/plugin-node-resolve': 15.3.1(rollup@4.34.9) | ||||
|       '@rollup/plugin-replace': 6.0.2(rollup@4.34.9) | ||||
|       '@rollup/plugin-typescript': 12.1.2(rollup@4.34.9)(tslib@2.8.1)(typescript@5.8.2) | ||||
|       '@types/node': 22.13.8 | ||||
|       '@types/node': 22.13.10 | ||||
|       chalk: 5.4.1 | ||||
|       commander: 12.1.0 | ||||
|       glob: 11.0.1 | ||||
| @@ -2334,16 +2428,16 @@ snapshots: | ||||
|     dependencies: | ||||
|       path-to-regexp: 8.2.0 | ||||
|       selfsigned: 2.4.1 | ||||
|       ws: 8.18.0 | ||||
|       ws: 8.18.1 | ||||
|     transitivePeerDependencies: | ||||
|       - bufferutil | ||||
|       - utf-8-validate | ||||
|  | ||||
|   '@kevisual/router@0.0.8-alpha.3': | ||||
|   '@kevisual/router@0.0.9': | ||||
|     dependencies: | ||||
|       path-to-regexp: 8.2.0 | ||||
|       selfsigned: 2.4.1 | ||||
|       ws: 8.18.0 | ||||
|       ws: 8.18.1 | ||||
|     transitivePeerDependencies: | ||||
|       - bufferutil | ||||
|       - utf-8-validate | ||||
| @@ -2430,7 +2524,7 @@ snapshots: | ||||
|     optionalDependencies: | ||||
|       rollup: 4.34.9 | ||||
|  | ||||
|   '@rollup/plugin-commonjs@28.0.2(rollup@4.34.9)': | ||||
|   '@rollup/plugin-commonjs@28.0.3(rollup@4.34.9)': | ||||
|     dependencies: | ||||
|       '@rollup/pluginutils': 5.1.4(rollup@4.34.9) | ||||
|       commondir: 1.0.1 | ||||
| @@ -2555,7 +2649,7 @@ snapshots: | ||||
|  | ||||
|   '@types/cors@2.8.17': | ||||
|     dependencies: | ||||
|       '@types/node': 22.13.8 | ||||
|       '@types/node': 22.13.10 | ||||
|  | ||||
|   '@types/crypto-js@4.2.2': {} | ||||
|  | ||||
| @@ -2567,16 +2661,16 @@ snapshots: | ||||
|  | ||||
|   '@types/formidable@3.4.5': | ||||
|     dependencies: | ||||
|       '@types/node': 22.13.8 | ||||
|       '@types/node': 22.13.10 | ||||
|  | ||||
|   '@types/fs-extra@8.1.5': | ||||
|     dependencies: | ||||
|       '@types/node': 22.13.8 | ||||
|       '@types/node': 22.13.10 | ||||
|  | ||||
|   '@types/glob@7.2.0': | ||||
|     dependencies: | ||||
|       '@types/minimatch': 5.1.2 | ||||
|       '@types/node': 22.13.8 | ||||
|       '@types/node': 22.13.10 | ||||
|  | ||||
|   '@types/lodash-es@4.17.12': | ||||
|     dependencies: | ||||
| @@ -2584,22 +2678,37 @@ snapshots: | ||||
|  | ||||
|   '@types/lodash@4.17.15': {} | ||||
|  | ||||
|   '@types/mime@1.3.5': {} | ||||
|  | ||||
|   '@types/minimatch@5.1.2': {} | ||||
|  | ||||
|   '@types/ms@2.1.0': {} | ||||
|  | ||||
|   '@types/node-forge@1.3.11': | ||||
|     dependencies: | ||||
|       '@types/node': 22.13.8 | ||||
|       '@types/node': 22.13.10 | ||||
|  | ||||
|   '@types/node@22.13.8': | ||||
|   '@types/node@22.13.10': | ||||
|     dependencies: | ||||
|       undici-types: 6.20.0 | ||||
|  | ||||
|   '@types/node@22.13.9': | ||||
|     dependencies: | ||||
|       undici-types: 6.20.0 | ||||
|  | ||||
|   '@types/resolve@1.20.2': {} | ||||
|  | ||||
|   '@types/send@0.17.4': | ||||
|     dependencies: | ||||
|       '@types/mime': 1.3.5 | ||||
|       '@types/node': 22.13.10 | ||||
|  | ||||
|   '@types/validator@13.12.2': {} | ||||
|  | ||||
|   '@types/ws@8.18.0': | ||||
|     dependencies: | ||||
|       '@types/node': 22.13.10 | ||||
|  | ||||
|   accepts@1.3.8: | ||||
|     dependencies: | ||||
|       mime-types: 2.1.35 | ||||
| @@ -2889,6 +2998,10 @@ snapshots: | ||||
|  | ||||
|   denque@2.1.0: {} | ||||
|  | ||||
|   depd@2.0.0: {} | ||||
|  | ||||
|   destroy@1.2.0: {} | ||||
|  | ||||
|   dezalgo@1.0.4: | ||||
|     dependencies: | ||||
|       asap: 2.0.6 | ||||
| @@ -2912,16 +3025,20 @@ snapshots: | ||||
|  | ||||
|   eastasianwidth@0.2.0: {} | ||||
|  | ||||
|   ee-first@1.1.1: {} | ||||
|  | ||||
|   emoji-regex@8.0.0: {} | ||||
|  | ||||
|   emoji-regex@9.2.2: {} | ||||
|  | ||||
|   encodeurl@2.0.0: {} | ||||
|  | ||||
|   engine.io-parser@5.2.3: {} | ||||
|  | ||||
|   engine.io@6.6.4: | ||||
|     dependencies: | ||||
|       '@types/cors': 2.8.17 | ||||
|       '@types/node': 22.13.8 | ||||
|       '@types/node': 22.13.10 | ||||
|       accepts: 1.3.8 | ||||
|       base64id: 2.0.0 | ||||
|       cookie: 0.7.2 | ||||
| @@ -3057,6 +3174,8 @@ snapshots: | ||||
|  | ||||
|   escalade@3.2.0: {} | ||||
|  | ||||
|   escape-html@1.0.3: {} | ||||
|  | ||||
|   escape-string-regexp@4.0.0: {} | ||||
|  | ||||
|   escodegen@2.1.0: | ||||
| @@ -3077,6 +3196,8 @@ snapshots: | ||||
|  | ||||
|   esutils@2.0.3: {} | ||||
|  | ||||
|   etag@1.8.1: {} | ||||
|  | ||||
|   eventemitter2@0.4.14: {} | ||||
|  | ||||
|   eventemitter2@5.0.1: {} | ||||
| @@ -3134,6 +3255,8 @@ snapshots: | ||||
|       hexoid: 2.0.0 | ||||
|       once: 1.4.0 | ||||
|  | ||||
|   fresh@0.5.2: {} | ||||
|  | ||||
|   fs-extra@8.1.0: | ||||
|     dependencies: | ||||
|       graceful-fs: 4.2.11 | ||||
| @@ -3278,6 +3401,14 @@ snapshots: | ||||
|  | ||||
|   hexoid@2.0.0: {} | ||||
|  | ||||
|   http-errors@2.0.0: | ||||
|     dependencies: | ||||
|       depd: 2.0.0 | ||||
|       inherits: 2.0.4 | ||||
|       setprototypeof: 1.2.0 | ||||
|       statuses: 2.0.1 | ||||
|       toidentifier: 1.0.1 | ||||
|  | ||||
|   http-proxy-agent@7.0.2: | ||||
|     dependencies: | ||||
|       agent-base: 7.1.3 | ||||
| @@ -3626,6 +3757,10 @@ snapshots: | ||||
|       has-symbols: 1.1.0 | ||||
|       object-keys: 1.1.1 | ||||
|  | ||||
|   on-finished@2.4.1: | ||||
|     dependencies: | ||||
|       ee-first: 1.1.1 | ||||
|  | ||||
|   once@1.4.0: | ||||
|     dependencies: | ||||
|       wrappy: 1.0.2 | ||||
| @@ -3834,6 +3969,8 @@ snapshots: | ||||
|  | ||||
|   queue-microtask@1.2.3: {} | ||||
|  | ||||
|   range-parser@1.2.1: {} | ||||
|  | ||||
|   read@1.0.7: | ||||
|     dependencies: | ||||
|       mute-stream: 0.0.8 | ||||
| @@ -4009,6 +4146,23 @@ snapshots: | ||||
|  | ||||
|   semver@7.7.1: {} | ||||
|  | ||||
|   send@1.1.0: | ||||
|     dependencies: | ||||
|       debug: 4.4.0(supports-color@5.5.0) | ||||
|       destroy: 1.2.0 | ||||
|       encodeurl: 2.0.0 | ||||
|       escape-html: 1.0.3 | ||||
|       etag: 1.8.1 | ||||
|       fresh: 0.5.2 | ||||
|       http-errors: 2.0.0 | ||||
|       mime-types: 2.1.35 | ||||
|       ms: 2.1.3 | ||||
|       on-finished: 2.4.1 | ||||
|       range-parser: 1.2.1 | ||||
|       statuses: 2.0.1 | ||||
|     transitivePeerDependencies: | ||||
|       - supports-color | ||||
|  | ||||
|   sequelize-pool@7.1.0: {} | ||||
|  | ||||
|   sequelize@6.37.5(pg@8.13.3): | ||||
| @@ -4056,6 +4210,8 @@ snapshots: | ||||
|       es-errors: 1.3.0 | ||||
|       es-object-atoms: 1.1.1 | ||||
|  | ||||
|   setprototypeof@1.2.0: {} | ||||
|  | ||||
|   shebang-command@2.0.0: | ||||
|     dependencies: | ||||
|       shebang-regex: 3.0.0 | ||||
| @@ -4166,6 +4322,8 @@ snapshots: | ||||
|  | ||||
|   standard-as-callback@2.1.0: {} | ||||
|  | ||||
|   statuses@2.0.1: {} | ||||
|  | ||||
|   stop-iteration-iterator@1.1.0: | ||||
|     dependencies: | ||||
|       es-errors: 1.3.0 | ||||
| @@ -4260,6 +4418,8 @@ snapshots: | ||||
|     dependencies: | ||||
|       is-number: 7.0.0 | ||||
|  | ||||
|   toidentifier@1.0.1: {} | ||||
|  | ||||
|   toposort-class@1.0.1: {} | ||||
|  | ||||
|   touch@3.1.1: {} | ||||
| @@ -4396,7 +4556,7 @@ snapshots: | ||||
|  | ||||
|   wkx@0.5.0: | ||||
|     dependencies: | ||||
|       '@types/node': 22.13.8 | ||||
|       '@types/node': 22.13.10 | ||||
|  | ||||
|   wrap-ansi@7.0.0: | ||||
|     dependencies: | ||||
| @@ -4416,7 +4576,7 @@ snapshots: | ||||
|  | ||||
|   ws@8.17.1: {} | ||||
|  | ||||
|   ws@8.18.0: {} | ||||
|   ws@8.18.1: {} | ||||
|  | ||||
|   xtend@4.0.2: {} | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								pnpm-workspace.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| packages: | ||||
|   - 'assistant-module' | ||||
							
								
								
									
										13
									
								
								src/app.ts
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/app.ts
									
									
									
									
									
								
							| @@ -1,8 +1,19 @@ | ||||
| import { App } from '@kevisual/router'; | ||||
| import { useContextKey } from '@kevisual/use-config/context'; | ||||
| import { httpsConfig } from './modules/config.ts'; | ||||
|  | ||||
| const init = () => { | ||||
|   return new App(); | ||||
|   const app = new App({ | ||||
|     serverOptions: { | ||||
|       path: '/client/router', | ||||
|       httpType: 'https', | ||||
|       httpsCert: httpsConfig.cert.toString(), | ||||
|       httpsKey: httpsConfig.key.toString(), | ||||
|     }, | ||||
|   }); | ||||
|   return app; | ||||
| }; | ||||
|  | ||||
| export const app = useContextKey('app', init); | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,16 +0,0 @@ | ||||
| import { app } from './app.ts'; | ||||
| import { useConfig } from '@kevisual/use-config'; | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'demo', | ||||
|     key: 'demo', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     ctx.body = '123'; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| const config = useConfig(); | ||||
|  | ||||
| console.log('run demo: http://localhost:' + config.port + '/api/router?path=demo&key=demo'); | ||||
							
								
								
									
										18
									
								
								src/dev.ts
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/dev.ts
									
									
									
									
									
								
							| @@ -1,8 +1,18 @@ | ||||
| import { useConfig } from '@kevisual/use-config'; | ||||
| import { app } from './index.ts'; | ||||
| import { proxyRoute } from './proxy-route/index.ts'; | ||||
|  | ||||
| const config = useConfig(); | ||||
| app | ||||
|   .route({ | ||||
|     path: 'demo', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     ctx.body = 'hello world'; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app.listen(config.port, () => { | ||||
|   console.log(`server is running at http://localhost:${config.port}`); | ||||
| console.log('httpsConfig', `https://localhost:51015/client/router?path=demo`); | ||||
| app.listen(51015, () => { | ||||
|   console.log('Router App is running on https://localhost:51015'); | ||||
| }); | ||||
|  | ||||
| app.server.on(proxyRoute); | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { app } from './app.ts'; | ||||
| import './demo-route.ts'; | ||||
| import './route/index.ts'; | ||||
|  | ||||
| export { app }; | ||||
							
								
								
									
										9
									
								
								src/modules/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/modules/config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| import fs from 'fs'; | ||||
| import path from 'path'; | ||||
|  | ||||
| const pemDir = path.join(process.cwd(), 'pem'); | ||||
|  | ||||
| export const httpsConfig = { | ||||
|   key: fs.readFileSync(path.join(pemDir, 'https-key.pem')), | ||||
|   cert: fs.readFileSync(path.join(pemDir, 'https-cert.pem')), | ||||
| }; | ||||
							
								
								
									
										108
									
								
								src/modules/config/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/modules/config/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| import path from 'path'; | ||||
| import { homedir } from 'os'; | ||||
| import fs from 'fs'; | ||||
| import { checkFileExists, createDir } from '../file/index.ts'; | ||||
|  | ||||
| export const kevisualUrl = 'https://kevisual.xiongxiao.me'; | ||||
| const configDir = createDir(path.join(homedir(), '.config/envision')); | ||||
| export const configPath = path.join(configDir, 'assistant-config.json'); | ||||
| export const appConfigPath = path.join(configDir, 'assistant-app-config.json'); | ||||
| export const appDir = createDir(path.join(configDir, 'assistant-app/frontend')); | ||||
| export const LocalElectronAppUrl = 'https://assistant.app/user/tiptap/'; | ||||
|  | ||||
| type AssistantConfig = { | ||||
|   pageApi?: string; // https://kevisual.silkyai.cn | ||||
|   loadURL?: string; // https://assistant.app/user/tiptap/ | ||||
|   proxy?: { user: string; key: string; path: string }[]; | ||||
| }; | ||||
| let assistantConfig: AssistantConfig; | ||||
| export const getConfig = () => { | ||||
|   try { | ||||
|     if (!checkFileExists(configPath)) { | ||||
|       fs.writeFileSync(configPath, JSON.stringify({ proxy: [] }, null, 2)); | ||||
|       return { | ||||
|         loadURL: LocalElectronAppUrl, | ||||
|         pageApi: '', | ||||
|         proxy: [], | ||||
|       }; | ||||
|     } | ||||
|     assistantConfig = JSON.parse(fs.readFileSync(configPath, 'utf8')); | ||||
|     return assistantConfig; | ||||
|   } catch (error) { | ||||
|     console.error(error); | ||||
|     return { | ||||
|       loadURL: LocalElectronAppUrl, | ||||
|       pageApi: '', | ||||
|       proxy: [], | ||||
|     }; | ||||
|   } | ||||
| }; | ||||
| export const getCacheAssistantConfig = () => { | ||||
|   if (assistantConfig) { | ||||
|     return assistantConfig; | ||||
|   } | ||||
|   return getConfig(); | ||||
| }; | ||||
|  | ||||
| export const setConfig = (config?: AssistantConfig) => { | ||||
|   if (!config) { | ||||
|     return assistantConfig; | ||||
|   } | ||||
|   assistantConfig = config; | ||||
|   fs.writeFileSync(configPath, JSON.stringify(config, null, 2)); | ||||
|   return assistantConfig; | ||||
| }; | ||||
| type AppConfig = { | ||||
|   list: any[]; | ||||
| }; | ||||
| /** | ||||
|  * 应用配置 | ||||
|  * @returns | ||||
|  */ | ||||
| export const getAppConfig = (): AppConfig => { | ||||
|   if (!checkFileExists(appConfigPath)) { | ||||
|     return { | ||||
|       list: [], | ||||
|     }; | ||||
|   } | ||||
|   return JSON.parse(fs.readFileSync(appConfigPath, 'utf8')); | ||||
| }; | ||||
|  | ||||
| export const setAppConfig = (config: AppConfig) => { | ||||
|   fs.writeFileSync(appConfigPath, JSON.stringify(config, null, 2)); | ||||
|   return config; | ||||
| }; | ||||
|  | ||||
| export const addAppConfig = (app: any) => { | ||||
|   const config = getAppConfig(); | ||||
|   const assistantConfig = getCacheAssistantConfig(); | ||||
|   const _apps = config.list; | ||||
|   const _proxy = assistantConfig.proxy || []; | ||||
|   const { user, key } = app; | ||||
|   const newProxyInfo = { | ||||
|     user, | ||||
|     key, | ||||
|     path: `/${user}/${key}`, | ||||
|   }; | ||||
|   const _proxyIndex = _proxy.findIndex((_proxy: any) => _proxy.path === newProxyInfo.path); | ||||
|   if (_proxyIndex !== -1) { | ||||
|     _proxy[_proxyIndex] = newProxyInfo; | ||||
|   } else { | ||||
|     _proxy.push(newProxyInfo); | ||||
|   } | ||||
|  | ||||
|   const _app = _apps.findIndex((_app: any) => _app.id === app.id); | ||||
|   if (_app !== -1) { | ||||
|     _apps[_app] = app; | ||||
|   } else { | ||||
|     _apps.push(app); | ||||
|   } | ||||
|   setAppConfig({ ...config, list: _apps }); | ||||
|   setConfig({ ...assistantConfig, proxy: _proxy }); | ||||
|   return config; | ||||
| }; | ||||
|  | ||||
| export const getAppList = () => { | ||||
|   const config = getAppConfig(); | ||||
|   return config.list || []; | ||||
| }; | ||||
							
								
								
									
										20
									
								
								src/modules/file/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/modules/file/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| import fs from 'fs'; | ||||
|  | ||||
| export const checkFileExists = (filePath: string, checkIsFile = false) => { | ||||
|   try { | ||||
|     fs.accessSync(filePath); | ||||
|     if (checkIsFile) { | ||||
|       return fs.statSync(filePath).isFile(); | ||||
|     } | ||||
|     return true; | ||||
|   } catch (error) { | ||||
|     return false; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export const createDir = (dirPath: string) => { | ||||
|   if (!checkFileExists(dirPath)) { | ||||
|     fs.mkdirSync(dirPath, { recursive: true }); | ||||
|   } | ||||
|   return dirPath; | ||||
| }; | ||||
							
								
								
									
										156
									
								
								src/modules/install.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								src/modules/install.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | ||||
| import path from 'path'; | ||||
| import fs from 'fs'; | ||||
| import { appDir, kevisualUrl, addAppConfig, getAppConfig, setAppConfig, getCacheAssistantConfig, setConfig } from './config/index.ts'; | ||||
|  | ||||
| export const demoData = { | ||||
|   id: '471ee96f-d7d8-4da1-b84f-4a34f4732f16', | ||||
|   title: 'tiptap', | ||||
|   description: '', | ||||
|   data: { | ||||
|     files: [ | ||||
|       { | ||||
|         name: 'README.md', | ||||
|         path: 'user/tiptap/0.0.1/README.md', | ||||
|       }, | ||||
|       { | ||||
|         name: 'app.css', | ||||
|         path: 'user/tiptap/0.0.1/app.css', | ||||
|       }, | ||||
|       { | ||||
|         name: 'app.js', | ||||
|         path: 'user/tiptap/0.0.1/app.js', | ||||
|       }, | ||||
|       { | ||||
|         name: 'create-BxEwtceK.js', | ||||
|         path: 'user/tiptap/0.0.1/create-BxEwtceK.js', | ||||
|       }, | ||||
|       { | ||||
|         name: 'index.CrTXFMOJ.js', | ||||
|         path: 'user/tiptap/0.0.1/index.CrTXFMOJ.js', | ||||
|       }, | ||||
|       { | ||||
|         name: 'index.html', | ||||
|         path: 'user/tiptap/0.0.1/index.html', | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   version: '0.0.1', | ||||
|   domain: '', | ||||
|   appType: '', | ||||
|   key: 'tiptap', | ||||
|   type: '', | ||||
|   uid: '2bebe6a0-3c64-4a64-89f9-cc47fd082a07', | ||||
|   pid: null, | ||||
|   proxy: false, | ||||
|   user: 'user', | ||||
|   status: 'running', | ||||
|   createdAt: '2024-12-14T15:39:30.684Z', | ||||
|   updatedAt: '2024-12-14T15:39:55.714Z', | ||||
|   deletedAt: null, | ||||
| }; | ||||
|  | ||||
| type DownloadTask = { | ||||
|   downloadPath: string; | ||||
|   downloadUrl: string; | ||||
|   user: string; | ||||
|   key: string; | ||||
|   version: string; | ||||
| }; | ||||
| export type Package = { | ||||
|   id: string; | ||||
|   name?: string; | ||||
|   version?: string; | ||||
|   description?: string; | ||||
|   title?: string; | ||||
|   user?: string; | ||||
|   key?: string; | ||||
|   [key: string]: any; | ||||
| }; | ||||
| export const installApp = async (app: Package) => { | ||||
|   // const _app = demoData; | ||||
|   const _app = app; | ||||
|   try { | ||||
|     let files = _app.data.files || []; | ||||
|     const version = _app.version; | ||||
|     const user = _app.user; | ||||
|     const key = _app.key; | ||||
|  | ||||
|     const downFiles = files.map((file: any) => { | ||||
|       const noVersionPath = file.path.replace(`/${version}`, ''); | ||||
|       return { | ||||
|         ...file, | ||||
|         downloadPath: path.join(appDir, noVersionPath), | ||||
|         downloadUrl: `${kevisualUrl}/${noVersionPath}`, | ||||
|       }; | ||||
|     }); | ||||
|     const downloadTasks: DownloadTask[] = downFiles as any; | ||||
|     for (const file of downloadTasks) { | ||||
|       const downloadPath = file.downloadPath; | ||||
|       const downloadUrl = file.downloadUrl; | ||||
|       const dir = path.dirname(downloadPath); | ||||
|       if (!fs.existsSync(dir)) { | ||||
|         fs.mkdirSync(dir, { recursive: true }); | ||||
|       } | ||||
|       const res = await fetch(downloadUrl); | ||||
|       const blob = await res.blob(); | ||||
|       fs.writeFileSync(downloadPath, Buffer.from(await blob.arrayBuffer())); | ||||
|     } | ||||
|     let indexHtml = files.find((file: any) => file.name === 'index.html'); | ||||
|     if (!indexHtml) { | ||||
|       files.push({ | ||||
|         name: 'index.html', | ||||
|         path: `${user}/${key}/index.html`, | ||||
|       }); | ||||
|       fs.writeFileSync(path.join(appDir, `${user}/${key}/index.html`), JSON.stringify(app, null, 2)); | ||||
|     } | ||||
|     _app.data.files = files; | ||||
|     addAppConfig(_app); | ||||
|     return { | ||||
|       code: 200, | ||||
|       data: _app, | ||||
|       message: 'Install app success', | ||||
|     }; | ||||
|   } catch (error) { | ||||
|     console.error(error); | ||||
|     return { | ||||
|       code: 500, | ||||
|       message: 'Install app failed', | ||||
|     }; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export const uninstallApp = async (app: Package) => { | ||||
|   try { | ||||
|     const { user, key } = app; | ||||
|     const appConfig = getAppConfig(); | ||||
|     const index = appConfig.list.findIndex((item: any) => item.user === user && item.key === key); | ||||
|     if (index !== -1) { | ||||
|       appConfig.list.splice(index, 1); | ||||
|       setAppConfig(appConfig); | ||||
|       // 删除appDir和文件 | ||||
|       fs.rmSync(path.join(appDir, user, key), { recursive: true }); | ||||
|       // 删除proxy | ||||
|       const proxyConfig = getCacheAssistantConfig(); | ||||
|       const proxyIndex = proxyConfig.proxy.findIndex((item: any) => item.user === user && item.key === key); | ||||
|       if (proxyIndex !== -1) { | ||||
|         proxyConfig.proxy.splice(proxyIndex, 1); | ||||
|         setConfig(proxyConfig); | ||||
|       } | ||||
|     } | ||||
|     return { | ||||
|       code: 200, | ||||
|       message: 'Uninstall app success', | ||||
|     }; | ||||
|   } catch (error) { | ||||
|     console.error(error); | ||||
|     return { | ||||
|       code: 500, | ||||
|       message: 'Uninstall app failed', | ||||
|     }; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export const getInstallList = async () => { | ||||
|   const appConfig = getAppConfig(); | ||||
|   return appConfig.list; | ||||
| }; | ||||
							
								
								
									
										61
									
								
								src/proxy-route/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/proxy-route/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| import { fileProxy, apiProxy, createApiProxy } from '@kevisual/assistant-module/proxy'; | ||||
| import { getCacheAssistantConfig, appDir } from '@kevisual/assistant-module'; | ||||
| import http from 'http'; | ||||
|  | ||||
| // https://localhost:51015/user/tiptap/ | ||||
| export const proxyRoute = async (req: http.IncomingMessage, res: http.ServerResponse) => { | ||||
|   const assistantConfig = getCacheAssistantConfig(); | ||||
|   // const { apiList } = assistantConfig; | ||||
|   const url = new URL(req.url, 'http://localhost'); | ||||
|   const pathname = url.pathname; | ||||
|   if (pathname.startsWith('/favicon.ico')) { | ||||
|     res.statusCode = 404; | ||||
|     res.end('Not Found Favicon'); | ||||
|     return; | ||||
|   } | ||||
|   if (pathname.startsWith('/client')) { | ||||
|     console.log('handle by router'); | ||||
|     return; | ||||
|   } | ||||
|   const apiProxyList = assistantConfig?.apiProxyList || []; | ||||
|   const defaultApiProxy = createApiProxy(assistantConfig?.pageApi || 'https://kevisual.xiongxiao.me'); | ||||
|   const apiBackendProxy = [...apiProxyList, ...defaultApiProxy].find((item) => pathname.startsWith(item.path)); | ||||
|   if (apiBackendProxy) { | ||||
|     console.log('apiBackendProxy', apiBackendProxy); | ||||
|     return apiProxy(req, res, { | ||||
|       path: apiBackendProxy.path, | ||||
|       target: apiBackendProxy.target, | ||||
|     }); | ||||
|   } | ||||
|   // client, api, v1, serve 开头的拦截 | ||||
|   const proxyApiList = assistantConfig?.proxy || []; | ||||
|   const proxyApi = proxyApiList.find((item) => pathname.startsWith(item.path)); | ||||
|   if (proxyApi) { | ||||
|     console.log('proxyApi', proxyApi, pathname); | ||||
|     const { user, key } = proxyApi; | ||||
|     return fileProxy(req, res, { | ||||
|       path: proxyApi.path, | ||||
|       rootPath: appDir, | ||||
|       indexPath: `${user}/${key}/index.html`, | ||||
|     }); | ||||
|   } | ||||
|   const localProxyProxy = localProxyProxyList.find((item) => pathname.startsWith(item.path)); | ||||
|   if (localProxyProxy) { | ||||
|     return fileProxy(req, res, { | ||||
|       path: localProxyProxy.path, | ||||
|       rootPath: process.cwd(), | ||||
|       indexPath: localProxyProxy.indexPath, | ||||
|     }); | ||||
|   } | ||||
|   console.log('handle by router 404'); | ||||
|   res.statusCode = 404; | ||||
|   res.end('Not Found Proxy'); | ||||
| }; | ||||
| const localProxyProxyList = [ | ||||
|   { | ||||
|     user: 'root', | ||||
|     key: 'assistant-base-app', | ||||
|     path: '/root/assistant-base-app', | ||||
|     indexPath: 'root/assistant-base-app/index.html', | ||||
|   }, | ||||
| ]; | ||||
							
								
								
									
										42
									
								
								src/proxy-route/ws-proxy.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/proxy-route/ws-proxy.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| import net from 'net'; | ||||
| import { App } from '@kevisual/router'; | ||||
|  | ||||
| export const wsProxy = (app: App, config: { apiList: any[] }) => { | ||||
|   console.log('Upgrade initialization started'); | ||||
|  | ||||
|   app.server.server.on('upgrade', (req, socket, head) => { | ||||
|     const proxyApiList = config?.apiList || []; | ||||
|     const proxyApi = proxyApiList.find((item) => req.url.startsWith(item.path)); | ||||
|  | ||||
|     if (proxyApi) { | ||||
|       const _u = new URL(req.url, `${proxyApi.target}`); | ||||
|       const options = { | ||||
|         hostname: _u.hostname, | ||||
|         port: Number(_u.port) || 80, | ||||
|         path: _u.pathname, | ||||
|         headers: req.headers, | ||||
|       }; | ||||
|  | ||||
|       const proxySocket = net.connect(options.port, options.hostname, () => { | ||||
|         proxySocket.write( | ||||
|           `GET ${options.path} HTTP/1.1\r\n` + | ||||
|             `Host: ${options.hostname}\r\n` + | ||||
|             `Connection: Upgrade\r\n` + | ||||
|             `Upgrade: websocket\r\n` + | ||||
|             `Sec-WebSocket-Key: ${req.headers['sec-websocket-key']}\r\n` + | ||||
|             `Sec-WebSocket-Version: ${req.headers['sec-websocket-version']}\r\n` + | ||||
|             `\r\n`, | ||||
|         ); | ||||
|         proxySocket.pipe(socket); | ||||
|         socket.pipe(proxySocket); | ||||
|       }); | ||||
|  | ||||
|       proxySocket.on('error', (err) => { | ||||
|         console.error(`WebSocket proxy error: ${err.message}`); | ||||
|         socket.end(); | ||||
|       }); | ||||
|     } else { | ||||
|       socket.end(); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
							
								
								
									
										10
									
								
								src/route/client/check.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/route/client/check.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| import { app } from '@/app.ts'; | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'check', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     ctx.body = 'ok'; | ||||
|   }) | ||||
|   .addTo(app); | ||||
							
								
								
									
										25
									
								
								src/route/config/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/route/config/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| import { app } from '@/app.ts'; | ||||
| import { getCacheAssistantConfig, setConfig } from '@/modules/config/index.ts'; | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'config', | ||||
|     description: '获取配置', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     ctx.body = getCacheAssistantConfig(); | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'config', | ||||
|     key: 'set', | ||||
|     description: '设置配置', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     const { data } = ctx.query; | ||||
|  | ||||
|     ctx.body = setConfig(data); | ||||
|   }) | ||||
|   .addTo(app); | ||||
							
								
								
									
										3
									
								
								src/route/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/route/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| import './shop-install/index.ts'; | ||||
| import './client/check.ts'; | ||||
| import './config/index.ts'; | ||||
							
								
								
									
										40
									
								
								src/route/shop-install/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/route/shop-install/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| import { app } from '@/app.ts'; | ||||
| import { getInstallList, installApp, uninstallApp } from '@/modules/install.ts'; | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'shop', | ||||
|     key: 'list-installed', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     // https://localhost:51015/client/router?path=shop&key=list-installed | ||||
|     const list = await getInstallList(); | ||||
|     ctx.body = list; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'shop', | ||||
|     key: 'install', | ||||
|   }) | ||||
|   .define(async (ctx) => { | ||||
|     // https://localhost:51015/client/router?path=shop&key=install | ||||
|     const { pkg } = ctx.query.data; | ||||
|     const res = await installApp(pkg); | ||||
|     ctx.body = res; | ||||
|   }) | ||||
|   .addTo(app); | ||||
|  | ||||
| app | ||||
|   .route({ | ||||
|     path: 'shop', | ||||
|     key: 'uninstall', | ||||
|   }) | ||||
|   .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; | ||||
|   }) | ||||
|   .addTo(app); | ||||
							
								
								
									
										8
									
								
								src/scripts/assistant-config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/scripts/assistant-config.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| import { getCacheAssistantConfig, appConfigPath, appDir } from '@kevisual/assistant-module'; | ||||
| import fs from 'fs'; | ||||
|  | ||||
| const assistantConfig = getCacheAssistantConfig(); | ||||
| console.log(assistantConfig); | ||||
|  | ||||
| console.log('appConfigPath', appConfigPath); | ||||
| console.log('appDir', appDir); | ||||
		Reference in New Issue
	
	Block a user