everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
219 lines (217 loc) • 10.4 kB
JavaScript
const require_services_registry_fastkv = require('../registry/fastkv.cjs');
const require_load = require('../resolution/load.cjs');
const require_process_env = require('../../env/process-env.cjs');
const require_service_descriptor = require('../dev/service-descriptor.cjs');
const require_runtime = require('../resolution/runtime.cjs');
const require_source = require('./source.cjs');
const require_driver = require('../../db/driver.cjs');
const require_project_env = require('../../env/project-env.cjs');
const require_artifacts = require('../codegen/artifacts.cjs');
const require_planner = require('../../infra/planner.cjs');
const require_progress = require('../dev/progress.cjs');
const require_boot = require('../dev/boot.cjs');
const require_published = require('../registry/published.cjs');
let effect = require("effect");
//#region src/services/start/boot.ts
var StartFetchFailed = class extends effect.Data.TaggedError("StartFetchFailed") {};
var StartRemoteConfigMissing = class extends effect.Data.TaggedError("StartRemoteConfigMissing") {};
var StartConfigMissing = class extends effect.Data.TaggedError("StartConfigMissing") {};
/**
* A production start booting from an explicit config has declared that config
* as its truth — the host's SnapshotWatch must not override it with the
* registry pointer mid-run (a fixture-booted stack carrying a live identity
* would otherwise adopt a foreign generation 30 seconds in, and a
* config-path production boot is the operator's declared truth). The watch
* stays on for identity-driven boots — adopting published config changes is
* its feature. An operator-set interval always wins.
*/
function setSnapshotWatchIntervalForBoot(source, env, processEnv = process.env) {
if (processEnv.BOS_SNAPSHOT_WATCH_INTERVAL_MS !== void 0) return;
if (env !== "production" || !source.configPath) return;
processEnv.BOS_SNAPSHOT_WATCH_INTERVAL_MS = "0";
}
const startBootstrap = (deps, input) => effect.Effect.gen(function* () {
const shell = yield* require_project_env.captureShellEnv;
const projectEnv = yield* require_project_env.ProjectEnv;
const sessionRoot = deps.session?.root ?? process.cwd();
yield* require_boot.loadEnvStep(projectEnv, sessionRoot);
yield* require_progress.emitProgress({
phase: "config",
status: "running"
});
const bosEnv = input.env ?? (require_process_env.getProcessEnv("BOS_ENV") === "staging" ? "staging" : "production");
const explicitConfig = require_source.resolveStartConfigSource(input, {
BOS_ACCOUNT: require_process_env.getProcessEnv("BOS_ACCOUNT"),
BOS_GATEWAY: require_process_env.getProcessEnv("BOS_GATEWAY")
});
const registry = input.registry ?? require_process_env.getProcessEnv("BOS_REGISTRY");
setSnapshotWatchIntervalForBoot(explicitConfig, bosEnv);
let config = null;
let remoteConfig = null;
if (explicitConfig.configPath) config = deps.session?.config ?? null;
else if (explicitConfig.registry) {
const { account, domain } = explicitConfig.registry;
const expectedUrl = require_services_registry_fastkv.buildRegistryConfigUrl(account, domain, registry);
remoteConfig = yield* effect.Effect.tryPromise({
try: () => require_published.resolvePublishedConfig(account, domain, registry),
catch: (error) => new StartFetchFailed({ message: `Failed to fetch config for bos://${account}/${domain}: ${error instanceof Error ? error.message : "Unknown error"}\nExpected URL: ${expectedUrl}` })
});
if (remoteConfig) config = remoteConfig;
else return yield* new StartRemoteConfigMissing({ message: `No config found at bos://${account}/${domain}. Verify the account and gateway are correct and the config has been published.\nExpected URL: ${expectedUrl}` });
} else config = deps.session?.config ?? null;
if (!config) return yield* new StartConfigMissing({});
if (!explicitConfig.configPath) {
if (explicitConfig.registry?.account) config = {
...config,
account: explicitConfig.registry.account
};
if (explicitConfig.registry?.domain) config = {
...config,
domain: explicitConfig.registry.domain
};
}
const baseConfig = config;
const port = input.port ?? require_runtime.getHostDevelopmentPort(baseConfig.app.host.development);
const isStaging = bosEnv === "staging";
const runtimePlugins = yield* effect.Effect.tryPromise({
try: () => require_runtime.buildRuntimePluginsForConfig(baseConfig, sessionRoot, "production"),
catch: (cause) => new require_boot.DevStepError({
phase: "resolve runtime plugins",
cause
})
});
const runtimeConfig = yield* effect.Effect.tryPromise({
try: () => require_runtime.buildRuntimeConfig(baseConfig, sessionRoot, "production", {
uiSource: "remote",
apiSource: "remote",
authSource: "remote",
hostSource: "remote",
plugins: runtimePlugins
}),
catch: (cause) => new require_boot.DevStepError({
phase: "build runtime config",
cause
})
});
if (isStaging && baseConfig.staging?.domain) runtimeConfig.domain = baseConfig.staging.domain;
if (isStaging) runtimeConfig.env = "staging";
yield* require_progress.emitProgress({
phase: "generate artifacts",
status: "running"
});
yield* effect.Effect.tryPromise({
try: () => require_artifacts.generateCodeArtifacts(sessionRoot, baseConfig, {
env: "production",
runtimeConfig
}),
catch: (cause) => new require_boot.DevStepError({
phase: "generate artifacts",
cause
})
});
yield* require_progress.emitProgress({
phase: "generate artifacts",
status: "done"
});
const productionEnv = {};
const warnings = [];
const localhostOrigin = /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i;
const corsOrigin = require_process_env.getProcessEnv("CORS_ORIGIN");
if (corsOrigin !== void 0 && localhostOrigin.test(corsOrigin) && require_source.isRegistryStart(explicitConfig)) {
warnings.push(`CORS_ORIGIN is a localhost origin (${corsOrigin}) in a registry production start — overriding with the configured domain`);
require_process_env.deleteProcessEnv("CORS_ORIGIN");
require_process_env.deleteProcessEnv("BASE_URL");
}
if (!require_process_env.getProcessEnv("CORS_ORIGIN") && baseConfig.domain) {
const defaultOrigin = `https://${isStaging ? baseConfig.staging?.domain ?? baseConfig.domain : baseConfig.domain}`;
productionEnv.CORS_ORIGIN = defaultOrigin;
productionEnv.BASE_URL = defaultOrigin;
warnings.push(`CORS_ORIGIN defaulting to ${defaultOrigin}`);
}
const requiredSecrets = /* @__PURE__ */ new Set();
const missingSecrets = [];
if (runtimeConfig.host.secrets) for (const s of runtimeConfig.host.secrets) requiredSecrets.add(s);
if (runtimeConfig.auth?.secrets) for (const s of runtimeConfig.auth.secrets) requiredSecrets.add(s);
if (runtimeConfig.api?.secrets) for (const s of runtimeConfig.api.secrets) requiredSecrets.add(s);
for (const plugin of Object.values(runtimeConfig.plugins ?? {})) if (plugin.secrets) for (const s of plugin.secrets) {
if (s.endsWith("_DATABASE_URL")) continue;
requiredSecrets.add(s);
}
for (const secret of requiredSecrets) {
const value = require_process_env.getProcessEnv(secret);
if (!value || value.length === 0) missingSecrets.push(secret);
}
if (missingSecrets.length > 0) warnings.push(`Missing ${missingSecrets.length} secret(s): ${missingSecrets.join(", ")}`);
for (const [secret, value] of Object.entries(require_process_env.processEnvRecord())) {
if (!value || !secret.endsWith("_DATABASE_URL")) continue;
if (require_driver.isRailwayPublicProxyUrl(value)) {
const host = new URL(value).hostname;
warnings.push(`${secret} points at Railway's public proxy (${host}) — its TLS certificate is self-signed, so connections use unverified TLS. Prefer the private *.railway.internal URL when the database runs in the same Railway project.`);
}
}
if (!require_process_env.operatorEnvRecord().API_DATABASE_URL && !require_process_env.operatorEnvRecord().AUTH_DATABASE_URL) warnings.push("No *_DATABASE_URL set — plugins without explicit URLs boot on ephemeral pglite and their data will not survive restarts. Set API_DATABASE_URL/AUTH_DATABASE_URL in .env for production.");
const stagingEnvVars = isStaging ? { BOS_GATEWAY: baseConfig.staging?.domain ?? baseConfig.domain ?? "" } : {};
const plan = yield* require_planner.planInfra({
configDir: sessionRoot,
bosConfig: runtimeConfig,
operatorEnv: require_process_env.operatorEnvRecord(),
cli: {
port: input.port,
ssr: false,
proxy: false,
hostSource: "remote",
uiSource: "remote",
apiSource: "remote",
authSource: "remote",
interactive: input.interactive
}
});
const services = require_service_descriptor.buildServiceDescriptorMap(plan.runtimeConfig);
const summary = {
configSource: explicitConfig.configPath ? explicitConfig.configPath : remoteConfig ? `bos://${explicitConfig.registry?.account}/${explicitConfig.registry?.domain}` : require_load.findConfigPath() ?? "bos.config.json",
configSourceHttp: remoteConfig && explicitConfig.registry ? require_services_registry_fastkv.buildRegistryConfigUrl(explicitConfig.registry.account, explicitConfig.registry.domain, registry) : void 0,
account: baseConfig.account,
domain: baseConfig.domain ?? void 0,
modules: {
host: plan.runtimeConfig.host.remoteUrl ?? plan.runtimeConfig.host.url ?? "local",
ui: plan.runtimeConfig.ui.url ?? "local",
api: plan.runtimeConfig.api.url ?? "local",
auth: plan.runtimeConfig.auth?.url ?? void 0
},
warnings
};
const orchestrator = {
packages: ["host"],
env: {
NODE_ENV: "production",
...productionEnv,
...stagingEnvVars,
...plan.launch.env
},
description: `${isStaging ? "Staging" : "Production"} Mode (${baseConfig.account})`,
port: plan.resolvedPorts.host ?? port,
interactive: input.interactive
};
yield* require_progress.emitProgress({
phase: "config",
status: "done"
});
return {
session: {
orchestrator,
services,
runtimeConfig: plan.runtimeConfig,
envGenerated: plan.envGenerated,
shellEnv: shell
},
summary,
url: plan.launch.hostUrl ?? `http://localhost:${plan.resolvedPorts.host ?? port}`
};
});
//#endregion
exports.StartConfigMissing = StartConfigMissing;
exports.StartFetchFailed = StartFetchFailed;
exports.StartRemoteConfigMissing = StartRemoteConfigMissing;
exports.setSnapshotWatchIntervalForBoot = setSnapshotWatchIntervalForBoot;
exports.startBootstrap = startBootstrap;
//# sourceMappingURL=boot.cjs.map