Files
g3n/bin/g3n.ts
bipproduction cd08c13ecf tambahan baru
2025-09-25 14:10:09 +08:00

156 lines
3.4 KiB
TypeScript
Executable File

#!/usr/bin/env bun
import minimist from "minimist";
import path from "path";
import { generateEnvTypes } from "../generate/env.generate";
import checkPort from "./src/port";
import route from "./src/route";
import compose from "./src/compose";
import generateDockerfile from "./src/docker-file";
import frp from "./src/frp";
import { version } from '../package.json' assert { type: 'json' };
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
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
Version: ${version}
`;
// 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;
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);
});