134 lines
4.3 KiB
TypeScript
134 lines
4.3 KiB
TypeScript
import { config } from 'dotenv';
|
|
import { existsSync } from 'node:fs';
|
|
import { homedir } from 'node:os';
|
|
import { dirname, join, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { detectFromEnv, loadConfig } from '@mosaicstack/config';
|
|
|
|
type TierSource =
|
|
| 'process environment'
|
|
| 'daemon .env'
|
|
| 'monorepo-root .env'
|
|
| 'gateway-local .env'
|
|
| 'default';
|
|
|
|
type BootSource = TierSource | 'mosaic.config.json';
|
|
|
|
export interface GatewayDotenvPaths {
|
|
daemonEnv: string;
|
|
monorepoRootEnv: string;
|
|
gatewayLocalEnv: string;
|
|
}
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
|
|
export function resolveGatewayDotenvPaths(
|
|
anchor: string = here,
|
|
homeBase: string = homedir(),
|
|
): GatewayDotenvPaths {
|
|
return {
|
|
daemonEnv: join(homeBase, '.config', 'mosaic', 'gateway', '.env'),
|
|
monorepoRootEnv: resolve(anchor, '../../..', '.env'),
|
|
gatewayLocalEnv: resolve(anchor, '..', '.env'),
|
|
};
|
|
}
|
|
|
|
export function resolveGatewayConfigPath(anchor: string = here): string {
|
|
// GATEWAY_HOME is daemon-created 0700; its env override adds no authority because env can set MOSAIC_STORAGE_TIER.
|
|
const gatewayHome = resolve(
|
|
process.env['MOSAIC_GATEWAY_HOME'] ?? join(homedir(), '.config', 'mosaic', 'gateway'),
|
|
);
|
|
const daemonConfig = join(gatewayHome, 'mosaic.config.json');
|
|
const gatewayLocalConfig = resolve(anchor, '..', 'mosaic.config.json');
|
|
const monorepoRootConfig = resolve(anchor, '../../..', 'mosaic.config.json');
|
|
|
|
if (existsSync(daemonConfig)) {
|
|
return daemonConfig;
|
|
}
|
|
if (existsSync(gatewayLocalConfig)) {
|
|
return gatewayLocalConfig;
|
|
}
|
|
if (existsSync(monorepoRootConfig)) {
|
|
return monorepoRootConfig;
|
|
}
|
|
|
|
return monorepoRootConfig;
|
|
}
|
|
|
|
export function loadGatewayEnv(anchor: string = here, homeBase: string = homedir()): void {
|
|
const { daemonEnv, monorepoRootEnv, gatewayLocalEnv } = resolveGatewayDotenvPaths(
|
|
anchor,
|
|
homeBase,
|
|
);
|
|
const inheritedTier = process.env['MOSAIC_STORAGE_TIER'];
|
|
let tierSource: TierSource = inheritedTier === undefined ? 'default' : 'process environment';
|
|
const inheritedDatabaseUrl = process.env['DATABASE_URL'];
|
|
let databaseUrlSource: TierSource =
|
|
inheritedDatabaseUrl === undefined ? 'default' : 'process environment';
|
|
|
|
function loadAnchoredDotenv(
|
|
path: string,
|
|
sourceLabel: Exclude<TierSource, 'process environment' | 'default'>,
|
|
): void {
|
|
if (!existsSync(path)) {
|
|
return;
|
|
}
|
|
|
|
const beforeTier = process.env['MOSAIC_STORAGE_TIER'];
|
|
const beforeDatabaseUrl = process.env['DATABASE_URL'];
|
|
config({ path, quiet: true });
|
|
|
|
if (
|
|
beforeTier === undefined &&
|
|
process.env['MOSAIC_STORAGE_TIER'] !== undefined &&
|
|
tierSource === 'default'
|
|
) {
|
|
tierSource = sourceLabel;
|
|
}
|
|
|
|
if (
|
|
beforeDatabaseUrl === undefined &&
|
|
process.env['DATABASE_URL'] !== undefined &&
|
|
databaseUrlSource === 'default'
|
|
) {
|
|
databaseUrlSource = sourceLabel;
|
|
}
|
|
}
|
|
|
|
// Load .env from daemon config dir (global install / daemon mode) first.
|
|
// It takes precedence over file-based local-dev configuration.
|
|
loadAnchoredDotenv(daemonEnv, 'daemon .env');
|
|
|
|
// Load .env from the anchored monorepo root, then fill any remaining values
|
|
// from apps/gateway/.env when present.
|
|
loadAnchoredDotenv(monorepoRootEnv, 'monorepo-root .env');
|
|
loadAnchoredDotenv(gatewayLocalEnv, 'gateway-local .env');
|
|
|
|
const envOnlyTier = detectFromEnv().tier;
|
|
const configPath = resolveGatewayConfigPath(anchor);
|
|
const anchoredConfigExists = existsSync(configPath);
|
|
const resolvedTier = loadConfig(configPath).tier;
|
|
const configuredTier = process.env['MOSAIC_STORAGE_TIER'];
|
|
const databaseUrlDeterminesTier = envOnlyTier === 'standalone' && configuredTier !== 'standalone';
|
|
const recognizedTierDeterminesTier =
|
|
(configuredTier === 'federated' ||
|
|
configuredTier === 'standalone' ||
|
|
configuredTier === 'local') &&
|
|
configuredTier === envOnlyTier;
|
|
|
|
let source: BootSource;
|
|
if (anchoredConfigExists) {
|
|
source = 'mosaic.config.json';
|
|
} else if (databaseUrlDeterminesTier && databaseUrlSource !== 'default') {
|
|
source = databaseUrlSource;
|
|
} else if (recognizedTierDeterminesTier && tierSource !== 'default') {
|
|
source = tierSource;
|
|
} else {
|
|
source = 'default';
|
|
}
|
|
|
|
console.info(`[gateway env] storage tier=${resolvedTier} source=${source}`);
|
|
}
|
|
|
|
loadGatewayEnv();
|