// CoreDeno Runtime Entry Point // Connects to CoreGO via gRPC over Unix socket. // Implements DenoService for module lifecycle management. // Must be first import — patches http2 before @grpc/grpc-js loads. import "./polyfill.ts"; import { createCoreClient, type CoreClient } from "./client.ts"; import { startDenoServer, type DenoServer } from "./server.ts"; import { ModuleRegistry } from "./modules.ts"; // Read required environment variables const coreSocket = Deno.env.get("CORE_SOCKET"); if (!coreSocket) { console.error("FATAL: CORE_SOCKET environment variable not set"); Deno.exit(1); } const denoSocket = Deno.env.get("DENO_SOCKET"); if (!denoSocket) { console.error("FATAL: DENO_SOCKET environment variable not set"); Deno.exit(1); } console.error(`CoreDeno: CORE_SOCKET=${coreSocket}`); console.error(`CoreDeno: DENO_SOCKET=${denoSocket}`); // 1. Create module registry const registry = new ModuleRegistry(); // 2. Start DenoService server (Go calls us here via JSON-RPC over Unix socket) let denoServer: DenoServer; try { denoServer = await startDenoServer(denoSocket, registry); console.error("CoreDeno: DenoService server started"); } catch (err) { console.error(`FATAL: failed to start DenoService server: ${err}`); Deno.exit(1); } // 3. Connect to CoreService (we call Go here) with retry let coreClient: CoreClient; { coreClient = createCoreClient(coreSocket); const maxRetries = 20; let connected = false; let lastErr: unknown; for (let i = 0; i < maxRetries; i++) { try { const timeoutCall = (p: Promise): Promise => Promise.race([ p, new Promise((_, reject) => setTimeout(() => reject(new Error("call timeout")), 2000), ), ]); await timeoutCall( coreClient.storeSet("_coredeno", "status", "connected"), ); const resp = await timeoutCall( coreClient.storeGet("_coredeno", "status"), ); if (resp.found && resp.value === "connected") { connected = true; break; } } catch (err) { lastErr = err; if (i < 3 || i === 9 || i === 19) { console.error(`CoreDeno: retry ${i}: ${err}`); } } await new Promise((r) => setTimeout(r, 250)); } if (!connected) { console.error( `FATAL: failed to connect to CoreService after retries, last error: ${lastErr}`, ); denoServer.close(); Deno.exit(1); } console.error("CoreDeno: CoreService client connected"); } // 4. Inject CoreClient into registry for I/O bridge registry.setCoreClient(coreClient); // 5. Signal readiness console.error("CoreDeno: ready"); // 6. Keep alive until SIGTERM const ac = new AbortController(); Deno.addSignalListener("SIGTERM", () => { console.error("CoreDeno: shutting down"); ac.abort(); }); try { await new Promise((_resolve, reject) => { ac.signal.addEventListener("abort", () => reject(new Error("shutdown"))); }); } catch { // Clean shutdown coreClient.close(); denoServer.close(); }