UNPKG

everything-dev

Version:

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

127 lines (125 loc) • 5.14 kB
const require_infra = require("../services/infra.cjs"); let node_fs = require("node:fs"); let node_path = require("node:path"); let effect = require("effect"); let dotenv = require("dotenv"); //#region src/env/legacy-databases.ts var LegacyMigrationError = class extends effect.Data.TaggedError("LegacyMigrationError") {}; /** * The compose-era local database convention (`bos dev` provisioned Postgres * via the committed docker-compose.yml): every `*_DATABASE_URL` pointed at * `postgres://everythingdev:everythingdev@localhost:<port>/<db>` on the * hardcoded 5432–5435 block. Those are exactly the opt-ins that made two * concurrent local projects fight over host ports. * * The compose-era convention is retired — local persistence is a * file-backed PGlite data dir (`.bos/db`), tests run on in-memory pglite. * `bos dev` repairs leftover state once, idempotently: * 1. `.env` lines whose URL matches the conventional shape (user, host, * and database name — port too, but drift ports like 5532 from the old * +100 allocator also match by name) are rewritten to the new defaults. * Any other `postgres://` URL is operator-owned and left alone. * 2. A leftover scaffold-shaped `docker-compose.yml` is moved to * `.bos/compose-retired/` rather than deleted; operator-authored * compose files (different service names/images) are untouched. */ const migrateLegacyComposeState = (configDir) => effect.Effect.try({ try: () => { const envPath = (0, node_path.join)(configDir, ".env"); const databaseUrlDrift = []; if ((0, node_fs.existsSync)(envPath)) { const raw = (0, node_fs.readFileSync)(envPath, "utf-8"); const parsed = (0, dotenv.config)({ path: envPath, quiet: true }).parsed ?? {}; const rewritten = rewrittenLegacyDatabaseValues({ file: parsed, raw }); if (rewritten.size > 0) { const updated = raw.split("\n").map((line) => { const match = /^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(line); if (!match) return line; const replacement = rewritten.get(match[1]); return replacement === void 0 ? line : `${match[1]}=${replacement}`; }); (0, node_fs.writeFileSync)(envPath, updated.join("\n")); for (const [key, to] of rewritten) databaseUrlDrift.push({ key, from: parsed[key] ?? "", to }); } } return { databaseUrlDrift, composeRelocated: relocateLegacyComposeFile(configDir) }; }, catch: (cause) => new LegacyMigrationError({ cause }) }).pipe(effect.Effect.orElseSucceed(() => ({ databaseUrlDrift: [], composeRelocated: false }))); /** Matches the compose-era URL shapes: the scaffolded user + localhost + the convention's database names. */ const LEGACY_DATABASE_NAME = /^(api_db|auth_db|api_test_db|auth_test_db)$/; function legacyMappingForUrl(rawUrl) { try { const url = new URL(rawUrl); if (url.protocol !== "postgres:" && url.protocol !== "postgresql:") return void 0; if (url.hostname !== "localhost" && url.hostname !== "127.0.0.1") return void 0; if (url.username !== "everythingdev" || url.password !== "everythingdev") return void 0; const databaseName = decodeURIComponent(url.pathname.replace(/^\//, "")); if (!LEGACY_DATABASE_NAME.test(databaseName)) return void 0; return databaseName.endsWith("_test_db") ? require_infra.PGLITE_TEST_DATABASE_URL : require_infra.PGLITE_DEV_DATABASE_URL; } catch { return; } } function rewrittenLegacyDatabaseValues(input) { const rewritten = /* @__PURE__ */ new Map(); for (const [key, value] of Object.entries(input.file)) { const match = value ? legacyMappingForUrl(value) : void 0; if (match !== void 0) { if (new RegExp(`^${key}=.+$`, "m").test(input.raw)) rewritten.set(key, match); } } return rewritten; } const SCAFFOLD_SERVICE_NAMES = /* @__PURE__ */ new Set([ "postgres-api", "postgres-auth", "postgres-api-test", "postgres-auth-test" ]); const SCAFFOLD_IMAGE_HINTS = [ "public.ecr.aws/docker/library/postgres", "docker.io/library/postgres", "postgres:17-alpine", "ghcr.io/nearbuilders/mirror-postgres" ]; function isScaffoldComposeFile(raw) { if (![...raw.matchAll(/^\s+-?\s*([a-z-]+):\s*$/gm)].map((match) => match[1] ?? "").some((name) => SCAFFOLD_SERVICE_NAMES.has(name))) return false; return SCAFFOLD_IMAGE_HINTS.some((hint) => raw.includes(hint)); } function relocateLegacyComposeFile(configDir) { const composePath = (0, node_path.join)(configDir, "docker-compose.yml"); if (!(0, node_fs.existsSync)(composePath)) return false; let raw; try { raw = (0, node_fs.readFileSync)(composePath, "utf-8"); } catch { return false; } if (!isScaffoldComposeFile(raw)) return false; const retiredDir = (0, node_path.join)(configDir, ".bos", "compose-retired"); (0, node_fs.mkdirSync)(retiredDir, { recursive: true }); (0, node_fs.renameSync)(composePath, (0, node_path.join)(retiredDir, "docker-compose.yml")); return true; } //#endregion exports.LegacyMigrationError = LegacyMigrationError; exports.migrateLegacyComposeState = migrateLegacyComposeState; exports.rewrittenLegacyDatabaseValues = rewrittenLegacyDatabaseValues; //# sourceMappingURL=legacy-databases.cjs.map