UNPKG

everything-dev

Version:

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

167 lines (165 loc) • 6.92 kB
import { frameworkOwnedHeaderComment } from "./scaffold/ownership.mjs"; import { pgliteTestUrl } from "../db/defaults.mjs"; import { PGLITE_DEFAULT_URL } from "../db/binding.mjs"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { randomBytes } from "node:crypto"; //#region src/services/infra.ts const HOST_SECRET = "CORS_ORIGIN"; const REDIS_PORT = 6379; const TEST_AUTH_SECRET = "regression-test-secret-do-not-use-in-production"; const VESTIGIAL_SECRETS = /* @__PURE__ */ new Set(["NEAR_RELAYER_PRIVATE_KEY_MAINNET", "NEAR_RELAYER_PRIVATE_KEY_TESTNET"]); /** * Local development conventions. Databases default to a persistent, * file-backed PGlite data dir per workspace process (`.bos/db`) — no ports, * no docker. Operators point a secret at a `postgres://` URL to demand a * shared server. The two-database split (auth separate from everything * else) survives independent of compose. */ const PGLITE_DEV_DATABASE_URL = PGLITE_DEFAULT_URL; const PGLITE_TEST_DATABASE_URL = pgliteTestUrl; function uniqueSecrets(values) { const secrets = []; const seen = /* @__PURE__ */ new Set(); for (const value of values) { if (!value || seen.has(value)) continue; seen.add(value); secrets.push(value); } return secrets; } function loadPortState(configDir) { if (!configDir) return {}; const statePath = join(configDir, ".bos", "infra-state.json"); if (!existsSync(statePath)) return {}; try { return { devPorts: JSON.parse(readFileSync(statePath, "utf-8")).devPorts }; } catch { return {}; } } function savePortState(configDir, state) { const statePath = join(configDir, ".bos", "infra-state.json"); mkdirSync(dirname(statePath), { recursive: true }); writeFileSync(statePath, `${JSON.stringify(state, null, 2)}\n`); } function normalizeDatabaseSlug(secret) { return secret.replace(/_DATABASE_URL$/, "").toLowerCase(); } function normalizeRedisSlug(secret) { return secret.replace(/_REDIS_URL$/, "").toLowerCase(); } function databaseUrl() { return PGLITE_DEV_DATABASE_URL; } function buildConventionalDatabases(secrets) { return uniqueSecrets(secrets.filter((secret) => secret.endsWith("_DATABASE_URL"))).sort((a, b) => normalizeDatabaseSlug(a).localeCompare(normalizeDatabaseSlug(b))).map((secret) => { return { secret, slug: normalizeDatabaseSlug(secret), url: databaseUrl() }; }); } function buildConventionalRedis(secrets) { return uniqueSecrets(secrets.filter((secret) => secret.endsWith("_REDIS_URL"))).sort((a, b) => normalizeRedisSlug(a).localeCompare(normalizeRedisSlug(b))).map((secret) => ({ secret, slug: normalizeRedisSlug(secret), port: REDIS_PORT, url: `redis://localhost:${REDIS_PORT}` })); } function testDatabaseUrl() { return PGLITE_TEST_DATABASE_URL; } function getSecretGroups(runtimeConfig) { const groups = []; const seen = /* @__PURE__ */ new Set(); const addGroup = (section, secrets) => { const filtered = secrets.filter((s) => { if (VESTIGIAL_SECRETS.has(s)) return false; if (seen.has(s)) return false; seen.add(s); return true; }); if (filtered.length > 0) groups.push({ section, secrets: filtered }); }; addGroup("app.host", uniqueSecrets([...runtimeConfig.host.secrets ?? [], HOST_SECRET])); addGroup("app.api", uniqueSecrets(runtimeConfig.api.secrets ?? [])); if (runtimeConfig.auth) addGroup("app.auth", uniqueSecrets(runtimeConfig.auth.secrets ?? [])); if (runtimeConfig.plugins) { for (const [pluginKey, plugin] of Object.entries(runtimeConfig.plugins)) if (plugin.secrets && plugin.secrets.length > 0) addGroup(`plugins.${pluginKey}`, plugin.secrets); } return groups; } function defaultSecretValue(secret, databases, redisConfigs, options) { if (secret === "BETTER_AUTH_SECRET") return options.forExample ? "" : randomBytes(32).toString("base64url"); if (secret === "CORS_ORIGIN") { if (options.forExample) return "http://localhost:3000"; if (typeof options.devHostPort === "number") return `http://localhost:${options.devHostPort}`; return "http://localhost:3000"; } if (options.forExample) return ""; return databases.get(secret)?.url ?? redisConfigs.get(secret)?.url ?? ""; } /** * Plugin `*_DATABASE_URL` secrets share the API database (the platform's * two-database contract), so they are not rendered as template entries — * the host falls back to `API_DATABASE_URL` when they are unset. */ function isFallbackDatabaseSecret(secret) { return secret.endsWith("_DATABASE_URL") && secret !== "API_DATABASE_URL" && secret !== "AUTH_DATABASE_URL"; } function renderEnvFile(groups, options) { const rendered = groups.map((group) => ({ section: group.section, secrets: group.secrets.filter((secret) => !isFallbackDatabaseSecret(secret)) })).filter((group) => group.secrets.length > 0); const allSecrets = rendered.flatMap((group) => group.secrets); const databaseMap = new Map(buildConventionalDatabases(allSecrets).map((entry) => [entry.secret, entry])); const redisMap = new Map(buildConventionalRedis(allSecrets).map((entry) => [entry.secret, entry])); const lines = options.forExample ? [ ...frameworkOwnedHeaderComment("hash").trimEnd().split("\n"), "", "# Generated from configured bos secrets", "# Update values as needed for your local environment", "" ] : [ "# Generated from configured bos secrets", "# Update values as needed for your local environment", "" ]; for (const group of rendered) { lines.push(`# ${group.section}`); for (const secret of group.secrets) { if (options.forExample && (secret.endsWith("_DATABASE_URL") || secret.endsWith("_REDIS_URL"))) lines.push(secret.endsWith("_REDIS_URL") ? "# Leave empty for dev defaults; set a redis:// URL to opt into a real Redis." : "# Leave empty for the persistent local PGlite default (.bos/db); set a postgres:// URL for production or shared access."); lines.push(`${secret}=${defaultSecretValue(secret, databaseMap, redisMap, options)}`); } lines.push(""); } return `${lines.join("\n")}\n`; } function renderEnvTestFile(groups) { const lines = [ "# Generated test environment — loaded by test suites instead of .env", "# Test databases run on in-memory pglite — no docker involved", "" ]; for (const group of groups) { const entries = []; for (const secret of group.secrets) if (secret === "BETTER_AUTH_SECRET") entries.push(`${secret}=${TEST_AUTH_SECRET}`); else if (secret.endsWith("_DATABASE_URL")) entries.push(`${secret}=${testDatabaseUrl()}`); if (entries.length > 0) { lines.push(`# ${group.section}`); lines.push(...entries); lines.push(""); } } return `${lines.join("\n")}\n`; } //#endregion export { PGLITE_DEV_DATABASE_URL, PGLITE_TEST_DATABASE_URL, buildConventionalDatabases, buildConventionalRedis, getSecretGroups, loadPortState, normalizeDatabaseSlug, renderEnvFile, renderEnvTestFile, savePortState }; //# sourceMappingURL=infra.mjs.map