generated from tailored/router-template
base module
This commit is contained in:
parent
479eaccf57
commit
b966ea68f2
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);
|
Loading…
x
Reference in New Issue
Block a user