ssh -L
This commit is contained in:
commit
8b136d1a5a
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
node_modules
|
||||
dist
|
||||
coverage
|
||||
|
||||
.DS_Store
|
||||
.env
|
||||
/logs
|
||||
|
17
ecosystem.config.cjs
Normal file
17
ecosystem.config.cjs
Normal file
@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'dev-app',
|
||||
script: 'tsx ./src/index.ts',
|
||||
log_date_format: 'YYYY-MM-DD HH:mm Z',
|
||||
output: './logs/dev-app.log', // 所有日志输出到这里
|
||||
error: './logs/dev-app.log', // 错误日志也写到同一个文件
|
||||
log_date_format: 'YYYY-MM-DD HH:mm:ss',
|
||||
watch: false,
|
||||
env: {
|
||||
PM2_COLOR: 'true', // 开启彩色日志
|
||||
},
|
||||
merge_logs: true, // 合并日志流
|
||||
},
|
||||
],
|
||||
};
|
30
package.json
Normal file
30
package.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "dev-app",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"app": {
|
||||
"type": "micro-app"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@9.8.0+sha512.8e4c3550fb500e808dbc30bb0ce4dd1eb614e30b1c55245f211591ec2cdf9c611cabd34e1364b42f564bd54b3945ed0f49d61d1bbf2ec9bd74b866fcdc723276",
|
||||
"devDependencies": {
|
||||
"@kevisual/router": "0.0.6-alpha-2",
|
||||
"@kevisual/types": "^0.0.1",
|
||||
"@kevisual/use-config": "^1.0.4",
|
||||
"@types/node": "^22.10.1",
|
||||
"typescript": "^5.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"esbuild": "^0.24.0",
|
||||
"nanoid": "^5.0.9",
|
||||
"sequelize": "^6.37.5",
|
||||
"sqlite3": "^5.1.7"
|
||||
}
|
||||
}
|
1554
pnpm-lock.yaml
generated
Normal file
1554
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
5
src/app.ts
Normal file
5
src/app.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { App } from '@kevisual/router';
|
||||
|
||||
export const app = new App();
|
||||
|
||||
app.listen(9998)
|
15
src/child/run.ts
Normal file
15
src/child/run.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { spawn, spawnSync } from 'child_process';
|
||||
import path from 'path';
|
||||
|
||||
const devPath = '/Users/xion/on/on-ai/packages/parsex-extensions';
|
||||
export const runDev = () => {
|
||||
const a = spawnSync('vite build --watch', {
|
||||
stdio: 'inherit',
|
||||
shell: true,
|
||||
cwd: path.resolve(devPath),
|
||||
env: process.env,
|
||||
});
|
||||
console.log('a===', a);
|
||||
};
|
||||
|
||||
runDev();
|
11
src/index.ts
Normal file
11
src/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { app } from './app.ts';
|
||||
import './route/ssh/list.ts';
|
||||
|
||||
app
|
||||
.call({
|
||||
path: 'ssh',
|
||||
key: 'list',
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
});
|
42
src/lib/build/a.ts
Normal file
42
src/lib/build/a.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { build } from 'esbuild';
|
||||
import { writeFileSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
|
||||
export async function transformToMJS(inputCode) {
|
||||
// 1. 使用 esbuild 转换代码
|
||||
const result = await build({
|
||||
stdin: {
|
||||
contents: inputCode,
|
||||
resolveDir: process.cwd(), // 当前目录为基准路径,用于解析文件路径
|
||||
loader: 'ts',
|
||||
},
|
||||
format: 'esm', // 输出为 ESM 格式
|
||||
outfile: 'output.mjs', // 输出文件路径
|
||||
write: false, // 不直接写入文件
|
||||
});
|
||||
|
||||
// 2. 将结果保存为 .mjs 文件
|
||||
const outputPath = resolve('./output.mjs');
|
||||
writeFileSync(outputPath, result.outputFiles[0].text);
|
||||
|
||||
console.log(`转换完成,文件已保存到: ${outputPath}`);
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
// 示例字符串代码
|
||||
const inputCode = `
|
||||
import path from 'path';
|
||||
import {nanoid} from 'nanoid';
|
||||
console.log(path.resolve(), nanoid(6));
|
||||
`;
|
||||
|
||||
const runCode = (filePath: string) => {
|
||||
const mjs = import(filePath);
|
||||
//
|
||||
};
|
||||
transformToMJS(inputCode)
|
||||
.then((outputPath) => {
|
||||
console.log(`生成的 MJS 文件路径: ${outputPath}`);
|
||||
runCode(outputPath);
|
||||
})
|
||||
.catch(console.error);
|
3
src/lib/ssh.ts
Normal file
3
src/lib/ssh.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { SSHManager } from './ssh/manager.ts';
|
||||
|
||||
export const sshManager = new SSHManager();
|
46
src/lib/ssh/manager.ts
Normal file
46
src/lib/ssh/manager.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { SSHServer, SSHValue } from './ssh.ts';
|
||||
|
||||
export class SSHManager {
|
||||
servers: SSHServer[] = [];
|
||||
constructor() {}
|
||||
addServer(server: SSHServer) {
|
||||
this.servers.push(server);
|
||||
}
|
||||
getServers() {
|
||||
return this.servers.map((server) => {
|
||||
return {
|
||||
name: server.name,
|
||||
isRunning: server.isRunning,
|
||||
values: server.values,
|
||||
};
|
||||
});
|
||||
}
|
||||
createServer(remote: string, values: SSHValue[]) {
|
||||
if (!remote) {
|
||||
console.error('remote 不能为空');
|
||||
return;
|
||||
}
|
||||
const has = this.servers.find((server) => server.name === remote);
|
||||
let flag = false;
|
||||
if (has && has.isRunning) {
|
||||
flag = true;
|
||||
has.stop();
|
||||
}
|
||||
const server = new SSHServer({ name: remote, values });
|
||||
if (flag) {
|
||||
setTimeout(() => {
|
||||
server.start(); // 重新启动
|
||||
}, 1000);
|
||||
} else {
|
||||
server.start();
|
||||
}
|
||||
this.addServer(server);
|
||||
return server;
|
||||
}
|
||||
stopServer(remote: string) {
|
||||
const server = this.servers.find((server) => server.name === remote);
|
||||
if (server) {
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
}
|
103
src/lib/ssh/ssh.ts
Normal file
103
src/lib/ssh/ssh.ts
Normal file
@ -0,0 +1,103 @@
|
||||
// ssh -L 8080:localhost:80 -L 9090:localhost:90 user@remote-server
|
||||
import { ChildProcess, spawn } from 'child_process';
|
||||
type Options = {
|
||||
name: string;
|
||||
values: SSHValue[];
|
||||
};
|
||||
export type SSHValue = {
|
||||
localPort: number;
|
||||
remoteHost: string; // localhost
|
||||
remotePort: number;
|
||||
remote?: string; //sky config配置
|
||||
status?: 'active' | 'inactive';
|
||||
};
|
||||
export const demos: SSHValue[] = [
|
||||
{
|
||||
localPort: 3000,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 3000,
|
||||
remote: 'diana',
|
||||
},
|
||||
{
|
||||
localPort: 5244,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 5244,
|
||||
remote: 'diana',
|
||||
},
|
||||
];
|
||||
export class SSHServer {
|
||||
name = 'diana';
|
||||
values: SSHValue[] = [];
|
||||
childProcess: ChildProcess | null = null;
|
||||
isRunning = false;
|
||||
constructor(opts?: Options) {
|
||||
this.name = opts?.name || this.name;
|
||||
this.values = opts?.values || demos;
|
||||
}
|
||||
start(options?: Options) {
|
||||
try {
|
||||
const remote = options?.name || this.name;
|
||||
const demos = options?.values || this.values;
|
||||
const _port = demos.filter((item) => item.status === 'active');
|
||||
if (_port.length === 0) {
|
||||
this.isRunning = false;
|
||||
return;
|
||||
}
|
||||
const params = _port
|
||||
.map((item) => {
|
||||
return ['-L', `${item.localPort}:${item.remoteHost}:${item.remotePort}`];
|
||||
})
|
||||
.flat();
|
||||
const childProcess = spawn(
|
||||
'ssh',
|
||||
[
|
||||
'-N', // 不执行远程命令
|
||||
// '-f', // 后台运行
|
||||
'-o',
|
||||
'ServerAliveInterval=60', // 每60秒发送一次心跳包
|
||||
'-o',
|
||||
'ServerAliveCountMax=3', // 尝试3次心跳失败后断开连接
|
||||
'-T',
|
||||
...params,
|
||||
remote,
|
||||
],
|
||||
{
|
||||
// stdio: 'ignore',
|
||||
stdio: 'inherit',
|
||||
killSignal: 'SIGINT',
|
||||
},
|
||||
);
|
||||
this.childProcess = childProcess;
|
||||
childProcess.stdout?.on('data', (data) => {
|
||||
console.log('childProcess', data.toString());
|
||||
});
|
||||
childProcess.on('error', (err: any) => {
|
||||
if (err.code === 'EADDRINUSE') {
|
||||
console.error('端口被占用:', err);
|
||||
return;
|
||||
}
|
||||
console.error('Failed to start SSH process:', err);
|
||||
});
|
||||
childProcess.on('exit', (code, signal) => {
|
||||
console.log('SSH process exited:', code, signal);
|
||||
this.isRunning = false;
|
||||
});
|
||||
this.isRunning = true;
|
||||
console.log('当前ssh -L 服务启动', this.name);
|
||||
// 监听的端口是
|
||||
// console.log('监听的端口是:', _port.map((item) => `[${item.localPort},${item.remotePort}]`).join(','));
|
||||
console.log('监听的端口是:', _port.map((item) => item.localPort).join(','));
|
||||
} catch (error) {
|
||||
console.error('启动失败:', error);
|
||||
}
|
||||
}
|
||||
stop() {
|
||||
if (this.childProcess) {
|
||||
console.log('正在停止 ssh -L 服务:', this.name);
|
||||
this.childProcess.kill(); // 发送默认信号 SIGTERM
|
||||
this.childProcess = undefined;
|
||||
} else {
|
||||
console.log('没有正在运行的 ssh -L 服务.');
|
||||
}
|
||||
}
|
||||
}
|
47
src/modules/get-config.ts
Normal file
47
src/modules/get-config.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
export const envisionPath = path.join(os.homedir(), '.config', 'envision');
|
||||
const configPath = path.join(os.homedir(), '.config', 'envision', 'config.json');
|
||||
|
||||
export const pidFilePath = path.join(envisionPath, 'app.pid');
|
||||
export const dbPath = path.join(envisionPath, 'db.sqlite');
|
||||
const envisionPidDir = path.join(envisionPath);
|
||||
export const getPidList = () => {
|
||||
const files = fs.readdirSync(envisionPidDir);
|
||||
const pidFiles = files.filter((file) => file.endsWith('.pid'));
|
||||
return pidFiles.map((file) => {
|
||||
const pid = fs.readFileSync(path.join(envisionPidDir, file), 'utf-8');
|
||||
return { pid, file: path.join(envisionPidDir, file) };
|
||||
});
|
||||
};
|
||||
export const writeVitePid = (pid: number) => {
|
||||
fs.writeFileSync(path.join(envisionPath, `vite-${pid}.pid`), pid.toString());
|
||||
};
|
||||
export const checkFileExists = (filePath: string) => {
|
||||
try {
|
||||
fs.accessSync(filePath, fs.constants.F_OK);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
export const getConfig = () => {
|
||||
if (!checkFileExists(envisionPath)) {
|
||||
fs.mkdirSync(envisionPath, { recursive: true });
|
||||
}
|
||||
if (checkFileExists(configPath)) {
|
||||
const config = fs.readFileSync(configPath, 'utf-8');
|
||||
try {
|
||||
return JSON.parse(config);
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
export const writeConfig = (config: Record<string, any>) => {
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
};
|
16
src/modules/sequelize.ts
Normal file
16
src/modules/sequelize.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Sequelize } from 'sequelize';
|
||||
import { dbPath } from './get-config.ts';
|
||||
|
||||
// connect to db
|
||||
export const sequelize = new Sequelize({
|
||||
dialect: 'sqlite',
|
||||
storage: dbPath,
|
||||
// logging: false,
|
||||
});
|
||||
|
||||
sequelize
|
||||
.authenticate({ logging: false })
|
||||
.then(() => {})
|
||||
.catch((err) => {
|
||||
console.error('Unable to connect to the database:', err);
|
||||
});
|
60
src/route/dev/model.ts
Normal file
60
src/route/dev/model.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { DataTypes, Model, Op } from 'sequelize';
|
||||
import { sequelize } from '@/modules/sequelize.ts';
|
||||
|
||||
type DevData = {
|
||||
cwd?: string; // 当前工作目录
|
||||
command: string; // 启动命令
|
||||
type: 'node' | 'shell' | 'script'; // 启动类型
|
||||
env?: Record<string, string>; // 环境变量
|
||||
keepalive?: boolean; // 是否保持运行, 让用户知道是不是保持运行的
|
||||
code?: string; // 代码
|
||||
status?: 'active' | 'inactive'; // 状态
|
||||
path?: string; // esbuild 打包路径,用于 node 启动
|
||||
};
|
||||
export type Dev = Partial<InstanceType<typeof DevModel>>;
|
||||
|
||||
/**
|
||||
* @description 本地开发 配置启动和程序关闭
|
||||
*/
|
||||
export class DevModel extends Model {
|
||||
declare id: string;
|
||||
declare title: string;
|
||||
declare description: string;
|
||||
declare data: DevData;
|
||||
}
|
||||
DevModel.init(
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
primaryKey: true,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
},
|
||||
title: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
defaultValue: '',
|
||||
},
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
data: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: false,
|
||||
defaultValue: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
paranoid: true,
|
||||
modelName: 'local_dev',
|
||||
freezeTableName: true, // 禁用表名复数化
|
||||
},
|
||||
);
|
||||
|
||||
DevModel.sync({
|
||||
alter: true,
|
||||
logging: false,
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
});
|
59
src/route/ssh/config.ts
Normal file
59
src/route/ssh/config.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { DataTypes, Model, Op } from 'sequelize';
|
||||
import { sequelize } from '@/modules/sequelize.ts';
|
||||
|
||||
type SSHModelData = {
|
||||
localPort: number;
|
||||
remoteHost: string; // localhost
|
||||
remotePort: number;
|
||||
status?: 'active' | 'inactive';
|
||||
};
|
||||
export type SSH = Partial<InstanceType<typeof SSHModel>>;
|
||||
|
||||
export class SSHModel extends Model {
|
||||
declare id: string;
|
||||
// declare title: string;
|
||||
declare description: string;
|
||||
declare configs: SSHModelData[];
|
||||
declare remote: string;
|
||||
}
|
||||
SSHModel.init(
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
primaryKey: true,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
},
|
||||
// title: {
|
||||
// type: DataTypes.TEXT,
|
||||
// allowNull: false,
|
||||
// defaultValue: '',
|
||||
// },
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
configs: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: false,
|
||||
defaultValue: [],
|
||||
},
|
||||
remote: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
defaultValue: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
paranoid: true,
|
||||
modelName: 'local_ssh',
|
||||
freezeTableName: true, // 禁用表名复数化
|
||||
},
|
||||
);
|
||||
|
||||
SSHModel.sync({
|
||||
alter: true,
|
||||
logging: false,
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
});
|
79
src/route/ssh/list.ts
Normal file
79
src/route/ssh/list.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { app } from '@/app.ts';
|
||||
import { SSHModel } from './model.ts';
|
||||
import { sshManager } from '@/lib/ssh.ts';
|
||||
import { exec } from 'child_process';
|
||||
|
||||
const init = async () => {
|
||||
const sshList = await SSHModel.findAll();
|
||||
sshList.forEach((ssh) => {
|
||||
sshManager.createServer(ssh.remote, ssh.configs);
|
||||
});
|
||||
};
|
||||
setTimeout(init, 1000);
|
||||
app
|
||||
.route({
|
||||
path: 'ssh',
|
||||
key: 'list',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const sshList = await SSHModel.findAll();
|
||||
ctx.body = sshList;
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'ssh',
|
||||
key: 'status',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
ctx.body = sshManager.getServers();
|
||||
})
|
||||
.addTo(app);
|
||||
app
|
||||
.route({
|
||||
path: 'ssh',
|
||||
key: 'update',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const data = ctx.query.data;
|
||||
const isExec = ctx.query.exec ?? true;
|
||||
const { description, configs, remote } = data;
|
||||
if (!remote) {
|
||||
ctx.throw(400, 'remote 不能为空');
|
||||
}
|
||||
let ssh = await SSHModel.findOne({ where: { remote } });
|
||||
if (!ssh) {
|
||||
ssh = await SSHModel.create({ description, configs, remote });
|
||||
}
|
||||
await ssh.update({ description, configs }, { where: { remote } });
|
||||
//
|
||||
if (isExec) {
|
||||
sshManager.createServer(remote, configs);
|
||||
}
|
||||
|
||||
ctx.body = ssh;
|
||||
})
|
||||
.addTo(app);
|
||||
|
||||
app
|
||||
.route({
|
||||
path: 'ssh',
|
||||
key: 'closePort',
|
||||
})
|
||||
.define(async (ctx) => {
|
||||
const port = ctx.query.port;
|
||||
if (!port) {
|
||||
ctx.throw(400, 'port 不能为空');
|
||||
}
|
||||
|
||||
exec(`lsof -i:${port} | grep LISTEN | awk '{print $2}' | xargs kill -9`, (killErr, stdout, stderr) => {
|
||||
if (killErr) {
|
||||
console.error(`Failed to kill process on port ${port}:`, killErr.message);
|
||||
} else {
|
||||
console.log(`Port ${port} is now free. Restarting process...`);
|
||||
}
|
||||
});
|
||||
ctx.body = 'ok';
|
||||
})
|
||||
.addTo(app);
|
59
src/route/ssh/model.ts
Normal file
59
src/route/ssh/model.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import { DataTypes, Model, Op } from 'sequelize';
|
||||
import { sequelize } from '@/modules/sequelize.ts';
|
||||
|
||||
type SSHModelData = {
|
||||
localPort: number;
|
||||
remoteHost: string; // localhost
|
||||
remotePort: number;
|
||||
status?: 'active' | 'inactive';
|
||||
};
|
||||
export type SSH = Partial<InstanceType<typeof SSHModel>>;
|
||||
|
||||
export class SSHModel extends Model {
|
||||
declare id: string;
|
||||
// declare title: string;
|
||||
declare description: string;
|
||||
declare configs: SSHModelData[];
|
||||
declare remote: string;
|
||||
}
|
||||
SSHModel.init(
|
||||
{
|
||||
id: {
|
||||
type: DataTypes.UUID,
|
||||
primaryKey: true,
|
||||
defaultValue: DataTypes.UUIDV4,
|
||||
},
|
||||
// title: {
|
||||
// type: DataTypes.TEXT,
|
||||
// allowNull: false,
|
||||
// defaultValue: '',
|
||||
// },
|
||||
description: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
},
|
||||
configs: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: false,
|
||||
defaultValue: [],
|
||||
},
|
||||
remote: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
defaultValue: '',
|
||||
},
|
||||
},
|
||||
{
|
||||
sequelize,
|
||||
paranoid: true,
|
||||
modelName: 'local_ssh',
|
||||
freezeTableName: true, // 禁用表名复数化
|
||||
},
|
||||
);
|
||||
|
||||
SSHModel.sync({
|
||||
alter: true,
|
||||
logging: false,
|
||||
}).catch((e) => {
|
||||
console.error(e);
|
||||
});
|
72
src/scripts/add-nisar.ts
Normal file
72
src/scripts/add-nisar.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { app } from '../app.ts';
|
||||
import '../index.ts';
|
||||
const sleep = (time: number) => new Promise((resolve) => setTimeout(resolve, time));
|
||||
const main = async () => {
|
||||
await sleep(3000);
|
||||
// console.log('add nisar')
|
||||
|
||||
app.call({
|
||||
path: 'ssh',
|
||||
key: 'update',
|
||||
payload: {
|
||||
exec: true,
|
||||
data: {
|
||||
remote: 'nisar',
|
||||
description: 'diana的项目ssl l关联',
|
||||
configs: [
|
||||
{
|
||||
localPort: 3000,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 3000,
|
||||
description: 'openweb ui',
|
||||
status: 'active',
|
||||
},
|
||||
{
|
||||
localPort: 5244,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 5244,
|
||||
description: 'alist',
|
||||
status: 'inactive',
|
||||
},
|
||||
{
|
||||
localPort: 3003,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 3003,
|
||||
description: 'onai api',
|
||||
status: 'inactive',
|
||||
},
|
||||
{
|
||||
localPort: 3002,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 3004,
|
||||
description: 'codeflow ui',
|
||||
status: 'inactive',
|
||||
},
|
||||
{
|
||||
localPort: 8000,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 8000,
|
||||
description: 'parsex python api',
|
||||
status: 'inactive',
|
||||
},
|
||||
{
|
||||
localPort: 9092,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 9092,
|
||||
description: 'kafka',
|
||||
status: 'inactive',
|
||||
},
|
||||
{
|
||||
localPort: 9200,
|
||||
remoteHost: 'localhost',
|
||||
remotePort: 9200,
|
||||
description: 'elasticsearch',
|
||||
status: 'inactive',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
main();
|
33
tsconfig.json
Normal file
33
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",
|
||||
],
|
||||
"declaration": true,
|
||||
"noEmit": false,
|
||||
"allowImportingTsExtensions": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"moduleResolution": "NodeNext",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"esModuleInterop": true,
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
],
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"typings.d.ts",
|
||||
"src/**/*.ts",
|
||||
"test/**/*.ts",
|
||||
],
|
||||
}
|
33
tsconfig/app-lib.tsconfig.json
Normal file
33
tsconfig/app-lib.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": [
|
||||
"typings.d.ts",
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user