everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
183 lines (181 loc) • 7.57 kB
JavaScript
const require_ownership = require('./scaffold/ownership.cjs');
let node_fs = require("node:fs");
let node_path = require("node:path");
let node_crypto = require("node:crypto");
//#region src/services/infra.ts
const POSTGRES_USER = "everythingdev";
const POSTGRES_PASSWORD = "everythingdev";
const AUTH_DATABASE_SECRET = "AUTH_DATABASE_URL";
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"]);
/**
* Fixed local-development database conventions. The committed
* docker-compose.yml provisions exactly these services/ports — nothing is
* derived from runtime config. Every non-auth `*_DATABASE_URL` secret shares
* the api database (schema-isolated per plugin); auth gets its own.
*/
const DEV_API_DB_PORT = 5432;
const DEV_AUTH_DB_PORT = 5433;
const TEST_API_DB_PORT = 5434;
const TEST_AUTH_DB_PORT = 5435;
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 = (0, node_path.join)(configDir, ".bos", "infra-state.json");
if (!(0, node_fs.existsSync)(statePath)) return {};
try {
return { devPorts: JSON.parse((0, node_fs.readFileSync)(statePath, "utf-8")).devPorts };
} catch {
return {};
}
}
function savePortState(configDir, state) {
const statePath = (0, node_path.join)(configDir, ".bos", "infra-state.json");
(0, node_fs.mkdirSync)((0, node_path.dirname)(statePath), { recursive: true });
(0, node_fs.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(port, databaseName) {
return `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${port}/${databaseName}`;
}
function buildConventionalDatabases(secrets) {
return uniqueSecrets(secrets.filter((secret) => secret.endsWith("_DATABASE_URL"))).sort((a, b) => normalizeDatabaseSlug(a).localeCompare(normalizeDatabaseSlug(b))).map((secret) => {
const slug = normalizeDatabaseSlug(secret);
const isAuth = secret === AUTH_DATABASE_SECRET;
const port = isAuth ? DEV_AUTH_DB_PORT : DEV_API_DB_PORT;
const databaseName = isAuth ? "auth_db" : "api_db";
return {
secret,
slug,
port,
databaseName,
url: databaseUrl(port, databaseName)
};
});
}
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(secret) {
const isAuth = secret === AUTH_DATABASE_SECRET;
return databaseUrl(isAuth ? TEST_AUTH_DB_PORT : TEST_API_DB_PORT, isAuth ? "auth_test_db" : "api_test_db");
}
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 ? "" : (0, node_crypto.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 ? [
...require_ownership.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 to run dev on ephemeral pglite; set a postgres:// URL to opt into compose Postgres.");
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 dedicated *-test docker-compose services",
""
];
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(secret)}`);
if (entries.length > 0) {
lines.push(`# ${group.section}`);
lines.push(...entries);
lines.push("");
}
}
return `${lines.join("\n")}\n`;
}
//#endregion
exports.buildConventionalDatabases = buildConventionalDatabases;
exports.buildConventionalRedis = buildConventionalRedis;
exports.getSecretGroups = getSecretGroups;
exports.loadPortState = loadPortState;
exports.normalizeDatabaseSlug = normalizeDatabaseSlug;
exports.renderEnvFile = renderEnvFile;
exports.renderEnvTestFile = renderEnvTestFile;
exports.savePortState = savePortState;
//# sourceMappingURL=infra.cjs.map