UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

142 lines (140 loc) • 4.46 kB
let effect = require("effect"); let node_net = require("node:net"); //#region src/infra/preflight.ts var PreflightConnectionError = class extends effect.Data.TaggedError("PreflightConnectionError") { get message() { return `Postgres connection failed: ${this.cause instanceof Error ? this.cause.message : String(this.cause)}`; } }; const scheduleTimeout = (ms, fn) => setTimeout(fn, ms); function parseLocalUrl(url) { try { const parsed = new URL(url); const host = parsed.hostname; if (host !== "localhost" && host !== "127.0.0.1" && host !== "::1") return null; const port = Number.parseInt(parsed.port, 10); if (Number.isNaN(port)) return { host, port: parsed.protocol === "redis:" ? 6379 : 5432 }; return { host, port }; } catch { return null; } } function checkTcpReachable(host, port, timeoutMs = 2e3) { return effect.Effect.callback((resume) => { const socket = (0, node_net.createConnection)({ host, port }); const timer = scheduleTimeout(timeoutMs, () => { socket.destroy(); resume(effect.Effect.succeed(false)); }); socket.once("connect", () => { clearTimeout(timer); socket.destroy(); resume(effect.Effect.succeed(true)); }); socket.once("error", () => { clearTimeout(timer); socket.destroy(); resume(effect.Effect.succeed(false)); }); }); } function checkPgConnection(url) { return effect.Effect.gen(function* () { if (!(yield* checkTcpReachable(new URL(url).hostname, Number(new URL(url).port) || 5432, 4e3))) return false; return yield* effect.Effect.tryPromise({ try: async () => { const { Pool } = await import("pg"); const pool = new Pool({ connectionString: url, connectionTimeoutMillis: 3e3 }); try { const client = await pool.connect(); try { await client.query("SELECT 1"); return true; } finally { client.release(); } } finally { await pool.end().catch(() => {}); } }, catch: (cause) => new PreflightConnectionError({ cause }) }).pipe(effect.Effect.orElseSucceed(() => false)); }); } function preflightTargetsFromEnv(env) { const targets = []; for (const [secret, value] of Object.entries(env)) { if (!value) continue; if (secret.endsWith("_DATABASE_URL")) { const parsed = parseLocalUrl(value); if (parsed) targets.push({ secret, host: parsed.host, port: parsed.port, kind: "postgres", url: value }); } else if (secret.endsWith("_REDIS_URL")) { const parsed = parseLocalUrl(value); if (parsed) targets.push({ secret, host: parsed.host, port: parsed.port, kind: "redis", url: value }); } } return targets; } function preflightLocalInfra(env, overrides) { const targets = preflightTargetsFromEnv(overrides ? { ...env, ...overrides } : env); if (targets.length === 0) return effect.Effect.succeed([]); return effect.Effect.forEach(targets, (target) => effect.Effect.gen(function* () { if (target.kind === "postgres") { if (yield* checkPgConnection(target.url)) return null; const tcpOk = yield* checkTcpReachable(target.host, target.port); const pluginContext = target.secret === "API_DATABASE_URL" || target.secret === "AUTH_DATABASE_URL" ? " Run `docker compose up -d --wait` to start local Postgres." : ` The plugin for ${target.secret} runs inside the local host process, so this DB must be reachable. Run \`docker compose up -d --wait\` to start local Postgres.`; if (tcpOk) return { secret: target.secret, host: target.host, port: target.port, error: `${target.secret} at ${target.host}:${target.port} is reachable but Postgres connection failed. Check credentials and database name.${pluginContext}`, tcpReachable: true }; return { secret: target.secret, host: target.host, port: target.port, error: `${target.secret} points to ${target.host}:${target.port} but nothing is listening.${pluginContext}`, tcpReachable: false }; } if (yield* checkTcpReachable(target.host, target.port)) return null; return { secret: target.secret, host: target.host, port: target.port, error: `${target.secret} points to ${target.host}:${target.port} but nothing is listening`, tcpReachable: false }; }), { concurrency: "unbounded" }).pipe(effect.Effect.map((results) => results.filter((r) => r !== null))); } //#endregion exports.preflightLocalInfra = preflightLocalInfra; //# sourceMappingURL=preflight.cjs.map