`pnpm doctor` and `startApi` each read their own subset of the same environment variables, and the subsets had drifted. Doctor never read `S3_*` or module secrets at all, so a correctly configured installation was told its object storage was "not configured" and every module requiring a bucket or a secret was reported blocked -- while the runtime, from the identical environment, bound those buckets and ran the modules. Both executables now map the environment through one `loadHostConfiguration(env)` in Core, which takes the environment as an argument and never reads `process.env` itself. Validation stays with the existing per-domain validators, so each caller keeps its own failure behaviour: startup refuses a rejected value, Doctor reports it as a sanitized code. Doctor's storage option becomes raw input like its mail option, so a half-configured provider is reported as a blocking configuration failure instead of throwing before a report exists. The outbound-email check -- computed, counted toward the result, but absent from every rendered section -- is now printed, and the rendered set is asserted against a real report so a future check cannot go missing the same way. Co-Authored-By: Claude Opus 5 <[email protected]>
40 lines
1.7 KiB
TypeScript
40 lines
1.7 KiB
TypeScript
import {
|
|
assertProductionDatabaseTransport,
|
|
type DatabaseTransportEnvironment,
|
|
type DatabaseTransportPolicy,
|
|
createDatabaseTransportPolicy,
|
|
} from "../database/transport.js";
|
|
import { loadHostConfiguration } from "../host/index.js";
|
|
|
|
/**
|
|
* The database transport policy for the small Core-owned executables — `pnpm migrations:plan`,
|
|
* `pnpm migrations:apply`, `pnpm modules:enable`, and the owner-bootstrap commands — resolved from
|
|
* the process environment.
|
|
*
|
|
* The mapping itself belongs to `loadHostConfiguration`, which `startApi` and `pnpm doctor` also
|
|
* call, so `NODE_ENV` and the two TLS variables have exactly one interpretation across every entry
|
|
* point. Environment *reading* still happens here, in the executable layer: the reusable Core
|
|
* database and migration constructors keep taking explicit typed inputs and never touch
|
|
* `process.env`.
|
|
*/
|
|
export function readDatabaseTransportFromEnvironment(): {
|
|
readonly environment: DatabaseTransportEnvironment;
|
|
readonly transport: DatabaseTransportPolicy;
|
|
} {
|
|
const host = loadHostConfiguration(process.env);
|
|
const transport = createDatabaseTransportPolicy(host.databaseTransport, {
|
|
environment: host.environment,
|
|
});
|
|
return { environment: host.environment, transport };
|
|
}
|
|
|
|
/**
|
|
* Resolves the policy and asserts it is safe for the given database URL before any client, pool,
|
|
* or connection is constructed. Throws the sanitized `DatabaseTransportError` otherwise.
|
|
*/
|
|
export function resolveExecutableDatabaseTransport(databaseUrl: string): DatabaseTransportPolicy {
|
|
const { environment, transport } = readDatabaseTransportFromEnvironment();
|
|
assertProductionDatabaseTransport(databaseUrl, transport, environment);
|
|
return transport;
|
|
}
|