70 lines
2.6 KiB
TypeScript
70 lines
2.6 KiB
TypeScript
import Fastify, { type FastifyInstance, type FastifyServerOptions } from "fastify";
|
|
import websocket from "@fastify/websocket";
|
|
import { resolveAccount, LOCAL_ACCOUNT_ID } from "./auth.js";
|
|
import { createOpencodeProbe } from "./opencode.js";
|
|
import gatewayModule from "./modules/trapos-cloud-gateway/index.js";
|
|
import { GatewayRegistry } from "./modules/trapos-cloud-gateway/registry.js";
|
|
import mcpModule from "./modules/mcp/index.js";
|
|
|
|
export type Config = {
|
|
host: string;
|
|
port: number;
|
|
serverPassword?: string;
|
|
requestTimeoutMs: number;
|
|
opencodeUrl?: string;
|
|
opencodeUsername: string;
|
|
opencodeServerPassword?: string;
|
|
// MCP HTTP endpoint (exec-lua / write-file / probe-computers). Bound to mcpHost,
|
|
// which defaults to 127.0.0.1 so the powerful tools stay local-only.
|
|
mcpEnabled: boolean;
|
|
mcpHost: string;
|
|
mcpPort: number;
|
|
mcpDefaultTimeoutMs: number;
|
|
mcpMaxTimeoutMs: number;
|
|
mcpProbeTimeoutMs: number;
|
|
logger: FastifyServerOptions["logger"];
|
|
};
|
|
|
|
const MAX_PAYLOAD_BYTES = 1024 * 1024; // ~1MB
|
|
|
|
// Composes the service: registry + opencode probe + auth seam, wired into the
|
|
// trapos-cloud-gateway module, plus an optional MCP app sharing the same registry.
|
|
// Never reads process.env (that is index.ts's job), so it is fully constructable
|
|
// from tests. The MCP app is a separate Fastify instance (its own host/port) so it
|
|
// can bind to localhost independently of the public gateway listener.
|
|
export async function createApp(
|
|
config: Config,
|
|
): Promise<{ app: FastifyInstance; mcpApp: FastifyInstance | null; registry: GatewayRegistry }> {
|
|
const app = Fastify({ logger: config.logger, disableRequestLogging: true });
|
|
|
|
const registry = new GatewayRegistry(app.log, config.requestTimeoutMs);
|
|
const probe = createOpencodeProbe({
|
|
opencodeUrl: config.opencodeUrl,
|
|
opencodeUsername: config.opencodeUsername,
|
|
opencodeServerPassword: config.opencodeServerPassword,
|
|
});
|
|
|
|
await app.register(websocket, { options: { maxPayload: MAX_PAYLOAD_BYTES } });
|
|
await app.register(gatewayModule, {
|
|
registry,
|
|
probe,
|
|
resolveAccount: (secret) => resolveAccount(secret, config.serverPassword),
|
|
});
|
|
|
|
const mcpApp = config.mcpEnabled ? await createMcpApp(config, registry) : null;
|
|
|
|
return { app, mcpApp, registry };
|
|
}
|
|
|
|
async function createMcpApp(config: Config, registry: GatewayRegistry): Promise<FastifyInstance> {
|
|
const mcpApp = Fastify({ logger: config.logger, disableRequestLogging: true });
|
|
await mcpApp.register(mcpModule, {
|
|
registry,
|
|
accountId: LOCAL_ACCOUNT_ID,
|
|
defaultTimeoutMs: config.mcpDefaultTimeoutMs,
|
|
maxTimeoutMs: config.mcpMaxTimeoutMs,
|
|
probeTimeoutMs: config.mcpProbeTimeoutMs,
|
|
});
|
|
return mcpApp;
|
|
}
|