everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
70 lines (68 loc) • 3.02 kB
JavaScript
import { getSecretGroups, renderEnvFile, renderEnvTestFile } from "../cli/infra.mjs";
import { InfraError } from "./types.mjs";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { Context, Effect, Layer } from "effect";
//#region src/infra/materializer.ts
var InfraMaterializer = class extends Context.Service()("InfraMaterializer") {};
function ensureDir(filePath) {
mkdirSync(dirname(filePath), { recursive: true });
}
function writeIfChanged(filePath, content) {
if (existsSync(filePath) && readFileSync(filePath, "utf-8") === content) return;
ensureDir(filePath);
writeFileSync(filePath, content);
}
function writeContentEffect(filePath, content, phase) {
return Effect.try({
try: () => writeIfChanged(filePath, content),
catch: (cause) => new InfraError({
phase,
message: `failed to write ${filePath}`,
cause
})
});
}
const makeMaterializer = () => ({
materializeTemplate: (configDir, runtimeConfig) => Effect.gen(function* () {
const groups = getSecretGroups(runtimeConfig);
yield* writeContentEffect(join(configDir, ".env.example"), renderEnvFile(groups, { forExample: true }), "materialize-env");
}),
materializeTestInfra: (configDir, runtimeConfig) => Effect.gen(function* () {
const groups = getSecretGroups(runtimeConfig);
yield* writeContentEffect(join(configDir, ".env.test"), renderEnvTestFile(groups), "materialize-env");
})
});
const InfraMaterializerLive = Layer.succeed(InfraMaterializer, makeMaterializer());
/**
* Single source of truth for "should we persist port state?".
* Lives next to the only thing that still persists dev ports (the planner).
*/
function shouldPersistPortState() {
return process.env.BOS_NO_PERSIST_PORTS !== "1" && process.env.BOS_TEST !== "1" && process.env.NODE_ENV !== "test";
}
/**
* True when the run is ephemeral (regression, CI, local test).
* In ephemeral mode we must not rewrite `.env.example` because it's a
* committed reference template — every regression run was previously
* baking the resolved regression port into it, polluting the file.
*/
function isEphemeralRun() {
return process.env.BOS_NO_PERSIST_PORTS === "1" || process.env.BOS_TEST === "1" || process.env.NODE_ENV === "test";
}
/**
* Orchestration helper: materializes the env templates in the canonical
* order. docker-compose.yml is a static committed file — nothing here
* generates or rewrites it.
*/
async function materializeViaLayer(configDir, runtimeConfig, options = {}) {
const ephemeral = options.ephemeral ?? isEphemeralRun();
await Effect.runPromise(Effect.gen(function* () {
const m = yield* InfraMaterializer;
if (!ephemeral) yield* m.materializeTemplate(configDir, runtimeConfig);
yield* m.materializeTestInfra(configDir, runtimeConfig);
}).pipe(Effect.provide(InfraMaterializerLive)));
}
//#endregion
export { InfraMaterializer, InfraMaterializerLive, isEphemeralRun, materializeViaLayer, shouldPersistPortState };
//# sourceMappingURL=materializer.mjs.map