import { RemoteIngressEdge } from './classes.remoteingressedge.js'; import { RemoteIngressHub, type IHubConfig, type TAllowedEdge } from './classes.remoteingresshub.js'; export * from './classes.remoteingresshub.js'; export * from './classes.remoteingressedge.js'; export * from './classes.token.js'; const usage = `remoteingress Usage: remoteingress hub [--tunnel-port 8443] [--target-host 127.0.0.1] remoteingress edge --token remoteingress edge --hub-host --edge-id --secret [--hub-port 8443] Environment: REMOTEINGRESS_MODE=hub|edge REMOTEINGRESS_TOKEN= REMOTEINGRESS_HUB_HOST= REMOTEINGRESS_HUB_PORT=8443 REMOTEINGRESS_EDGE_ID= REMOTEINGRESS_SECRET= REMOTEINGRESS_TARGET_HOST=127.0.0.1 REMOTEINGRESS_ALLOWED_EDGES_JSON='[{"id":"edge-1","secret":"secret","listenPorts":[80,443]}]' `; const readArg = (args: string[], name: string): string | undefined => { const prefix = `--${name}=`; const inlineValue = args.find((arg) => arg.startsWith(prefix)); if (inlineValue) { return inlineValue.slice(prefix.length); } const index = args.indexOf(`--${name}`); if (index >= 0) { return args[index + 1]; } return undefined; }; const readNumber = (value: string | undefined, fallback: number): number => { if (!value) { return fallback; } const parsed = Number(value); if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) { throw new Error(`Invalid port: ${value}`); } return parsed; }; const readJson = (value: string | undefined, fallback: T): T => { if (!value) { return fallback; } return JSON.parse(value) as T; }; const waitForever = async (stop: () => Promise) => { let stopping = false; const handleStop = async () => { if (stopping) { return; } stopping = true; await stop(); process.exit(0); }; process.once('SIGINT', () => void handleStop()); process.once('SIGTERM', () => void handleStop()); await new Promise(() => {}); }; export const runCli = async () => { const args = process.argv.slice(2); if (args.includes('--help') || args.includes('-h')) { console.log(usage); return; } const positionalMode = args[0]?.startsWith('--') ? undefined : args[0]; const mode = readArg(args, 'mode') ?? positionalMode ?? process.env.REMOTEINGRESS_MODE; if (mode === 'hub') { const hub = new RemoteIngressHub(); const config: IHubConfig = { tunnelPort: readNumber(readArg(args, 'tunnel-port') ?? process.env.REMOTEINGRESS_TUNNEL_PORT, 8443), targetHost: readArg(args, 'target-host') ?? process.env.REMOTEINGRESS_TARGET_HOST ?? '127.0.0.1', tls: { certPem: readArg(args, 'tls-cert-pem') ?? process.env.REMOTEINGRESS_TLS_CERT_PEM, keyPem: readArg(args, 'tls-key-pem') ?? process.env.REMOTEINGRESS_TLS_KEY_PEM, }, performance: readJson(readArg(args, 'performance-json') ?? process.env.REMOTEINGRESS_PERFORMANCE_JSON, undefined), }; await hub.start(config); const allowedEdges = readJson( readArg(args, 'allowed-edges-json') ?? process.env.REMOTEINGRESS_ALLOWED_EDGES_JSON, [], ); if (allowedEdges.length > 0) { await hub.updateAllowedEdges(allowedEdges); } console.log(`RemoteIngress hub listening on ${config.tunnelPort}`); await waitForever(() => hub.stop()); return; } if (mode === 'edge') { const edge = new RemoteIngressEdge(); const token = readArg(args, 'token') ?? process.env.REMOTEINGRESS_TOKEN; if (token) { await edge.start({ token }); } else { const hubHost = readArg(args, 'hub-host') ?? process.env.REMOTEINGRESS_HUB_HOST; const edgeId = readArg(args, 'edge-id') ?? process.env.REMOTEINGRESS_EDGE_ID; const secret = readArg(args, 'secret') ?? process.env.REMOTEINGRESS_SECRET; if (!hubHost || !edgeId || !secret) { throw new Error('Edge mode requires --token or --hub-host, --edge-id, and --secret'); } await edge.start({ hubHost, hubPort: readNumber(readArg(args, 'hub-port') ?? process.env.REMOTEINGRESS_HUB_PORT, 8443), edgeId, secret, bindAddress: readArg(args, 'bind-address') ?? process.env.REMOTEINGRESS_BIND_ADDRESS, transportMode: readArg(args, 'transport-mode') as any, }); } console.log('RemoteIngress edge started'); await waitForever(() => edge.stop()); return; } console.log(usage); };