185 lines
3.9 KiB
TypeScript
Executable File
185 lines
3.9 KiB
TypeScript
Executable File
#!/usr/bin/env bun
|
|
import minimist from "minimist";
|
|
import os from "os";
|
|
import path from "path";
|
|
|
|
import compose from "./src/compose";
|
|
import generateDockerfile from "./src/docker-file";
|
|
import frp from "./src/frp";
|
|
import { generateEnvTypes } from "./src/generate/env.generate";
|
|
import checkPort from "./src/port";
|
|
import route from "./src/route";
|
|
|
|
import { version } from '../package.json' assert { type: 'json' };
|
|
import appCreate from "./src/app-create";
|
|
|
|
|
|
interface CheckPortResult {
|
|
port: number;
|
|
open: boolean;
|
|
}
|
|
|
|
// Default constants (12-Factor App)
|
|
const DEFAULTS = {
|
|
ENV_FILE: ".env",
|
|
ENV_OUT: "types/env.d.ts",
|
|
PORT_START: 3000,
|
|
PORT_END: 4000,
|
|
HOST: "127.0.0.1",
|
|
};
|
|
|
|
// CLI Help
|
|
const HELP_TEXT = `
|
|
g3n [command] [options]
|
|
|
|
Commands:
|
|
env Generate env.d.ts from .env file
|
|
scan-port Scan port range (default 3000-4000)
|
|
route Generate routes.ts from AppRoutes.tsx
|
|
compose Generate compose.yml from name
|
|
docker-file Generate Dockerfile
|
|
frp Show frp proxy list
|
|
app-create Generate app with Elysia and React
|
|
|
|
Options:
|
|
--env Path ke file .env (default: .env)
|
|
--out Path file output (default: types/env.d.ts)
|
|
--start Port awal scan (default: 3000)
|
|
--end Port akhir scan (default: 4000)
|
|
--host Host/IP target (default: 127.0.0.1)
|
|
|
|
Examples:
|
|
g3n env --env .env.local --out src/types/env.d.ts
|
|
g3n scan-port --start 7700 --end 7800 --host 127.0.0.1
|
|
g3n route
|
|
g3n compose <name>
|
|
g3n docker-file
|
|
g3n frp
|
|
g3n app-create <name>
|
|
|
|
Version: ${version}
|
|
`;
|
|
|
|
const g3nConf = path.join(os.homedir(), ".g3n.conf");
|
|
|
|
if (!(await Bun.file(g3nConf).exists())) {
|
|
const conf = `
|
|
# CODE
|
|
CODE_TOKEN=
|
|
|
|
# FRP
|
|
FRP_HOST=
|
|
FRP_USER=
|
|
FRP_SECRET=
|
|
`
|
|
Bun.write(g3nConf, conf);
|
|
console.log(`✅ G3N config created at ${g3nConf}`);
|
|
}
|
|
|
|
|
|
// Parse CLI arguments
|
|
const args = minimist(process.argv.slice(2));
|
|
|
|
/**
|
|
* Main CLI handler
|
|
*/
|
|
async function main(): Promise<void> {
|
|
const [command, name] = args._;
|
|
|
|
switch (command) {
|
|
case "env":
|
|
handleEnv();
|
|
break;
|
|
|
|
case "scan-port":
|
|
await handleScanPort();
|
|
break;
|
|
|
|
case "route":
|
|
route();
|
|
break;
|
|
|
|
case "compose":
|
|
handleCompose(name);
|
|
break;
|
|
|
|
case "docker-file":
|
|
generateDockerfile();
|
|
break;
|
|
case "frp":
|
|
frp().catch((err) => {
|
|
console.error("❌ Error:", err);
|
|
process.exit(1);
|
|
});
|
|
break;
|
|
case "app-create":
|
|
if (!name) {
|
|
console.error("❌ App name is required");
|
|
return;
|
|
}
|
|
appCreate({ appName: name });
|
|
break;
|
|
|
|
default:
|
|
console.error(HELP_TEXT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle "env" command
|
|
*/
|
|
function handleEnv(): void {
|
|
const envFile = args.env || DEFAULTS.ENV_FILE;
|
|
const output = args.out || DEFAULTS.ENV_OUT;
|
|
|
|
generateEnvTypes({
|
|
envFilePath: envFile,
|
|
outputDir: path.dirname(output),
|
|
outputFileName: path.basename(output),
|
|
});
|
|
|
|
console.log(`✅ Env types generated at ${output}`);
|
|
}
|
|
|
|
/**
|
|
* Handle "scan-port" command
|
|
*/
|
|
async function handleScanPort(): Promise<void> {
|
|
const start = Number(args.start) || DEFAULTS.PORT_START;
|
|
const end = Number(args.end) || DEFAULTS.PORT_END;
|
|
const host = args.host || DEFAULTS.HOST;
|
|
|
|
console.log(`🔍 Scanning ports ${start}-${end} on host ${host}...`);
|
|
|
|
const ports = Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
|
|
const results: CheckPortResult[] = await Promise.all(
|
|
ports.map((port) => checkPort(port, host))
|
|
);
|
|
|
|
const openPorts = results.filter((r) => r.open);
|
|
openPorts.forEach((r) => console.log(`✅ Port ${r.port} is open`));
|
|
|
|
console.log("✅ Scan completed");
|
|
}
|
|
|
|
/**
|
|
* Handle "compose" command
|
|
*/
|
|
function handleCompose(name?: string): void {
|
|
if (!name) {
|
|
console.error("❌ Compose name is required");
|
|
return;
|
|
}
|
|
|
|
compose(name);
|
|
console.log(`✅ Compose file generated for ${name}`);
|
|
}
|
|
|
|
// Execute CLI
|
|
main().catch((err) => {
|
|
console.error("❌ Unexpected error:", err);
|
|
process.exit(1);
|
|
});
|