everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1,200 lines (1,198 loc) • 45.4 kB
JavaScript
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
const require_fastkv = require('./fastkv.cjs');
const require_merge = require('./merge.cjs');
const require_network = require('./network.cjs');
const require_types = require('./types.cjs');
const require_config = require('./config.cjs');
const require_contract = require('./contract.cjs');
const require_integrity = require('./integrity.cjs');
const require_app = require('./app.cjs');
const require_shared_deps = require('./shared-deps.cjs');
const require_run = require('./utils/run.cjs');
const require_theme = require('./utils/theme.cjs');
const require_build = require('./build.cjs');
const require_infra = require('./cli/infra.cjs');
const require_save_config = require('./utils/save-config.cjs');
const require_cli_init = require('./cli/init.cjs');
const require_status = require('./cli/status.cjs');
const require_sync = require('./cli/sync.cjs');
const require_upgrade = require('./cli/upgrade.cjs');
const require_code_artifacts = require('./code-artifacts.cjs');
const require_near_cli = require('./near-cli.cjs');
const require_publish = require('./publish.cjs');
const require_service_descriptor = require('./service-descriptor.cjs');
let node_fs = require("node:fs");
let node_path = require("node:path");
let effect = require("effect");
let node_events = require("node:events");
let node_process = require("node:process");
node_process = require_runtime.__toESM(node_process, 1);
let every_plugin = require("every-plugin");
let zod = require("zod");
//#region src/plugin.ts
const pluginEvents = new node_events.EventEmitter();
let pendingSession = null;
let pendingStartSummary = null;
function consumeDevSession() {
const data = pendingSession;
const summary = pendingStartSummary;
pendingSession = null;
pendingStartSummary = null;
if (!data) return null;
return summary ? {
...data,
summary
} : data;
}
async function timePhase(timings, name, fn) {
pluginEvents.emit("progress", {
phase: name,
status: "running"
});
const startedAt = Date.now();
try {
const result = await fn();
timings.push({
name,
durationMs: Date.now() - startedAt
});
pluginEvents.emit("progress", {
phase: name,
status: "done",
durationMs: Date.now() - startedAt
});
return result;
} catch (error) {
pluginEvents.emit("progress", {
phase: name,
status: "error",
durationMs: Date.now() - startedAt
});
throw error;
}
}
const PUBLISH_FUNCTION_NAMES = ["__fastdata_kv"];
function parseSourceMode(value, defaultValue) {
if (value === "local" || value === "remote") return value;
return defaultValue;
}
function buildConfigResult(bosConfig, full = false) {
const packages = bosConfig?.app && typeof bosConfig.app === "object" ? Object.keys(bosConfig.app) : [];
const remotes = packages.filter((name) => name !== "host");
return {
config: bosConfig ?? null,
packages,
remotes,
full
};
}
function isValidProxyUrl(url) {
try {
const parsed = new URL(url);
return parsed.protocol === "http:" || parsed.protocol === "https:";
} catch {
return false;
}
}
function resolveProxyUrl(bosConfig) {
if (!bosConfig) return null;
const apiConfig = bosConfig.app.api;
if (!apiConfig) return null;
if (apiConfig.proxy && isValidProxyUrl(apiConfig.proxy)) return apiConfig.proxy;
if (apiConfig.production && isValidProxyUrl(apiConfig.production)) return apiConfig.production;
return null;
}
function sanitizePluginKey(value) {
return value.replace(/[^A-Za-z0-9/_-]/g, "-").replace(/\/+/g, "/").split("/").filter(Boolean).map((segment) => segment.replace(/[^A-Za-z0-9_-]/g, "-")).join("/").replace(/^\/+|\/+$/g, "");
}
function defaultPluginKey(source) {
const normalized = source.replace(/^local:/, "").replace(/\/$/, "");
if (source.startsWith("local:")) return sanitizePluginKey((0, node_path.basename)(normalized)) || "plugin";
try {
const url = new URL(source);
return sanitizePluginKey((0, node_path.basename)(url.pathname) || url.hostname) || "plugin";
} catch {
return sanitizePluginKey(source) || "plugin";
}
}
function pluginLocalPath(configDir, attachment) {
const ref = require_build.getPluginRef(attachment);
const source = ref?.development ?? ref?.production;
if (!source?.startsWith("local:")) return null;
return (0, node_path.join)(configDir, source.slice(6));
}
function listPluginAttachments(config) {
return Object.entries(config?.plugins ?? {}).map(([key, attachment]) => {
const ref = require_build.getPluginRef(attachment);
return {
key,
development: ref?.development,
production: ref?.production,
localPath: ref?.development?.startsWith("local:") ? ref.development.slice(6) : void 0,
source: ref?.development?.startsWith("local:") ? "local" : "remote",
integrity: ref?.integrity,
version: ref?.version,
name: ref?.name
};
}).sort((a, b) => a.key.localeCompare(b.key));
}
async function resolveRemoteConfigChain(accountId, gatewayId, visited) {
const selfRef = `bos://${accountId}/${gatewayId}`;
if (visited.has(selfRef)) throw new Error(`Circular extends detected: ${selfRef}`);
const nextVisited = new Set(visited);
nextVisited.add(selfRef);
const config = await require_fastkv.fetchBosConfigFromFastKv(selfRef);
const parentRef = config.extends ? require_merge.resolveExtendsRef(config.extends, "production") : void 0;
let merged;
if (!parentRef) merged = config;
else {
const { accountId: parentAccountId, gatewayId: parentGatewayId } = require_fastkv.parseBosUrl(parentRef);
merged = require_merge.mergeBosConfigWithExtends(await resolveRemoteConfigChain(parentAccountId, parentGatewayId, nextVisited), config);
}
return require_config.resolveConfigComposableEntries(require_types.BosConfigSchema.parse(merged), node_process.default.cwd(), "production");
}
async function fetchPublishedConfig(accountId, gatewayId) {
try {
return await resolveRemoteConfigChain(accountId, gatewayId, /* @__PURE__ */ new Set());
} catch (error) {
if (error instanceof Error && error.message.startsWith("No config found")) return null;
throw error;
}
}
var plugin_default = (0, every_plugin.createPlugin)({
variables: zod.z.object({ configPath: zod.z.string().optional() }),
secrets: zod.z.object({}),
contract: require_contract.bosContract,
initialize: (config) => effect.Effect.promise(async () => {
const configResult = await require_config.loadResolvedConfig({ path: config.variables.configPath });
return {
bosConfig: configResult?.config ?? null,
runtimeConfig: configResult?.runtime ?? null,
configDir: require_config.getProjectRoot()
};
}),
shutdown: () => effect.Effect.void,
createRouter: (deps, builder) => ({
config: builder.config.handler(async ({ input }) => {
if (input.full) return buildConfigResult(deps.bosConfig, true);
return buildConfigResult((await require_config.loadLocalConfig({ cwd: deps.configDir }))?.config ?? null, false);
}),
pluginAdd: builder.pluginAdd.handler(async ({ input }) => {
if (!deps.bosConfig) return {
status: "error",
key: "",
error: "No bos.config.json found"
};
const isBosRef = input.source.startsWith("bos://");
const isLocal = input.source.startsWith("local:");
const key = sanitizePluginKey(input.as ?? (isBosRef ? input.source.split("/").pop() ?? "plugin" : defaultPluginKey(input.source)));
const existing = deps.bosConfig.plugins?.[key];
const existingEntry = existing && typeof existing === "object" ? existing : {};
const nextPlugins = { ...deps.bosConfig.plugins ?? {} };
if (isBosRef) nextPlugins[key] = {
...existingEntry,
extends: input.source
};
else if (isLocal) nextPlugins[key] = {
...existingEntry,
development: input.source,
...existingEntry.extends ? {} : {}
};
else nextPlugins[key] = {
...existingEntry,
production: input.production ?? input.source
};
deps.bosConfig = {
...deps.bosConfig,
plugins: nextPlugins
};
await require_save_config.saveBosConfig(deps.configDir, deps.bosConfig);
await require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig);
const stored = deps.bosConfig.plugins?.[key];
const storedObj = stored && typeof stored === "object" ? stored : {};
return {
status: "added",
key,
development: storedObj.development,
production: storedObj.production,
integrity: storedObj.integrity,
version: storedObj.version
};
}),
pluginRemove: builder.pluginRemove.handler(async ({ input }) => {
if (!deps.bosConfig) return {
status: "error",
key: input.key,
error: "No bos.config.json found"
};
if (!deps.bosConfig.plugins?.[input.key]) return {
status: "error",
key: input.key,
error: `Plugin '${input.key}' is not configured`
};
const nextPlugins = { ...deps.bosConfig.plugins ?? {} };
delete nextPlugins[input.key];
deps.bosConfig = {
...deps.bosConfig,
plugins: Object.keys(nextPlugins).length > 0 ? nextPlugins : void 0
};
await require_save_config.saveBosConfig(deps.configDir, deps.bosConfig);
await require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig);
return {
status: "removed",
key: input.key
};
}),
pluginList: builder.pluginList.handler(async () => {
return {
status: "listed",
plugins: listPluginAttachments(deps.bosConfig)
};
}),
pluginPublish: builder.pluginPublish.handler(async ({ input }) => {
if (!deps.bosConfig) return {
status: "error",
key: input.key,
error: "No bos.config.json found"
};
const attachment = deps.bosConfig.plugins?.[input.key];
if (!attachment) return {
status: "error",
key: input.key,
error: `Plugin '${input.key}' is not configured`
};
const attachmentRef = require_build.getPluginRef(attachment);
const localPath = pluginLocalPath(deps.configDir, attachment);
if (!localPath) return {
status: "error",
key: input.key,
error: `Plugin '${input.key}' does not have a local development path`
};
const pkgPath = (0, node_path.join)(localPath, "package.json");
if (!await require_build.fileExists(pkgPath)) return {
status: "error",
key: input.key,
error: `Missing package.json at ${localPath}`
};
const pkgJson = await require_build.readJsonFile(pkgPath);
const script = pkgJson.scripts?.deploy ? "deploy" : "build";
const { stdout, stderr, exitCode } = await require_run.run("bun", ["run", script], {
cwd: localPath,
capture: true
});
if (exitCode !== 0) {
if (stdout.trim()) node_process.default.stdout.write(stdout);
if (stderr.trim()) node_process.default.stderr.write(stderr);
return {
status: "error",
key: input.key,
error: `Publish failed with exit code ${exitCode}`
};
}
if (stdout.trim()) node_process.default.stdout.write(stdout);
if (stderr.trim()) node_process.default.stderr.write(stderr);
const output = `${stdout}\n${stderr}`;
const deployEntry = require_integrity.parseDeployLines(output).find((e) => e.urlField === `plugins.${input.key}.production`);
let publishedUrl;
let integrity;
if (deployEntry) {
publishedUrl = deployEntry.url;
integrity = deployEntry.integrity;
} else {
publishedUrl = require_publish.extractPublishedUrl(output) ?? void 0;
integrity = publishedUrl ? await require_integrity.computeSriHashForUrl(publishedUrl) ?? void 0 : void 0;
}
let manifest = null;
if (publishedUrl) manifest = await require_fastkv.fetchRemotePluginManifest(publishedUrl);
else if (attachmentRef?.production) {
manifest = await require_fastkv.fetchRemotePluginManifest(attachmentRef.production);
if (manifest) publishedUrl = attachmentRef.production;
}
const version = manifest?.plugin.version ?? pkgJson.version;
if (publishedUrl) {
const rootConfigPath = (0, node_path.join)(deps.configDir, "bos.config.json");
try {
const rootConfig = JSON.parse((0, node_fs.readFileSync)(rootConfigPath, "utf-8"));
if (!rootConfig.plugins || typeof rootConfig.plugins !== "object") rootConfig.plugins = {};
const plugins = rootConfig.plugins;
if (!plugins[input.key] || typeof plugins[input.key] !== "object") plugins[input.key] = {};
const entry = plugins[input.key];
entry.production = publishedUrl;
if (integrity) entry.integrity = integrity;
else delete entry.integrity;
(0, node_fs.writeFileSync)(rootConfigPath, `${JSON.stringify(rootConfig, null, 2)}\n`);
console.log(` ✅ Updated bos.config.json: plugins.${input.key}.production`);
} catch (err) {
console.error(` ❌ Failed to update bos.config.json:`, err instanceof Error ? err.message : err);
}
await require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig);
}
return {
status: "published",
key: input.key,
path: localPath,
script,
production: publishedUrl ?? attachmentRef?.production,
integrity: integrity ?? void 0,
version: version ?? void 0
};
}),
dev: builder.dev.handler(async ({ input }) => {
const devTimings = [];
require_infra.ensureEnvFile(deps.configDir);
require_infra.loadProjectEnv(deps.configDir);
const localPackages = require_app.detectLocalPackages(deps.bosConfig ?? void 0, deps.runtimeConfig ?? void 0);
const hostSource = localPackages.includes("host") ? parseSourceMode(input.host, "local") : "remote";
const uiSource = localPackages.includes("ui") ? parseSourceMode(input.ui, "local") : "remote";
const apiSource = localPackages.includes("api") ? parseSourceMode(input.api, "local") : "remote";
const authSource = localPackages.includes("auth") ? parseSourceMode(input.auth, "local") : "remote";
const ssr = input.ssr ?? false;
const proxy = input.proxy ?? false;
const sharedSync = await timePhase(devTimings, "shared deps", () => require_shared_deps.syncResolvedSharedDeps({
configDir: deps.configDir,
hostMode: hostSource,
bosConfig: deps.bosConfig ?? void 0,
extendsChain: []
}));
let configMayHaveChanged = false;
if (sharedSync.catalogChanged) {
await timePhase(devTimings, "install", () => require_run.run("bun", ["install"], { cwd: deps.configDir }));
configMayHaveChanged = true;
}
const shouldBuildPlugin = apiSource === "local" && !proxy || localPackages.some((pkg) => pkg.startsWith("plugin:"));
await timePhase(devTimings, "build", async () => {
const buildTasks = [require_build.buildEverythingDevQuietly(deps.configDir)];
if (shouldBuildPlugin) buildTasks.push(require_build.buildEveryPluginQuietly(deps.configDir));
await Promise.all(buildTasks);
});
let devExtendsChain;
if (configMayHaveChanged || input.remotePlugins?.length) {
const refreshed = await timePhase(devTimings, "resolve config", () => require_config.loadResolvedConfig({
cwd: deps.configDir,
remotePlugins: input.remotePlugins
}));
deps.bosConfig = refreshed?.config ?? deps.bosConfig;
deps.runtimeConfig = refreshed?.runtime ?? deps.runtimeConfig;
devExtendsChain = refreshed?.source.extended;
}
if (!deps.bosConfig) return {
status: "error",
description: "No bos.config.json found",
processes: [],
timings: devTimings
};
if (proxy && !resolveProxyUrl(deps.bosConfig)) return {
status: "error",
description: "No valid proxy URL configured in bos.config.json",
processes: [],
timings: devTimings
};
const hostPort = input.port ?? require_config.getHostDevelopmentPort(deps.bosConfig.app.host.development);
require_config.suppressWarnings();
const developmentRuntime = require_app.buildRuntimeConfig(deps.bosConfig, {
uiSource,
apiSource,
authSource,
hostSource,
env: "development",
plugins: deps.runtimeConfig?.plugins
});
require_config.drainConfigWarnings();
require_config.resumeWarnings();
const runtimeConfig = await timePhase(devTimings, "ports", () => require_app.prepareDevelopmentRuntimeConfig(developmentRuntime, {
hostPort,
ssr
}));
require_infra.syncGeneratedInfra(deps.configDir, runtimeConfig);
require_infra.ensureEnvFile(deps.configDir);
require_infra.loadProjectEnv(deps.configDir);
await timePhase(devTimings, "generate artifacts", () => require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig, {
env: "development",
extendsChain: devExtendsChain,
runtimeConfig
}));
const services = require_service_descriptor.buildServiceDescriptorMap(runtimeConfig, {
ssr,
proxy
});
const packages = [...services.keys()];
if (node_process.default.env.DEBUG === "true" || node_process.default.env.DEBUG === "1") {
console.error("[DEBUG dev] services keys:", packages.join(", "));
console.error("[DEBUG dev] services sources:", packages.map((k) => `${k}=${services.get(k)?.source ?? "?"}`).join(", "));
console.error("[DEBUG dev] runtimeConfig.plugins keys:", Object.keys(runtimeConfig.plugins ?? {}).join(", "));
console.error("[DEBUG dev] runtimeConfig.plugins sources:", Object.entries(runtimeConfig.plugins ?? {}).map(([k, v]) => `${k}=${v.source}`).join(", "));
}
const displayEnv = {};
if (services.get("api")?.proxy) {
const proxyUrl = resolveProxyUrl(deps.bosConfig);
if (proxyUrl) displayEnv.API_PROXY = proxyUrl;
}
const orchestrator = {
packages,
env: displayEnv,
description: require_service_descriptor.buildDescription(services),
port: runtimeConfig.host.port,
interactive: input.interactive
};
pendingSession = {
orchestrator,
services,
runtimeConfig
};
return {
status: "started",
description: orchestrator.description,
processes: packages,
timings: devTimings
};
}),
start: builder.start.handler(async ({ input }) => {
require_infra.ensureEnvFile(deps.configDir);
require_infra.loadProjectEnv(deps.configDir);
pluginEvents.emit("progress", {
phase: "config",
status: "running"
});
const bosEnv = input.env ?? (node_process.default.env.BOS_ENV === "staging" ? "staging" : "production");
const account = input.account ?? node_process.default.env.BOS_ACCOUNT;
const domain = input.domain ?? node_process.default.env.BOS_GATEWAY;
let config = null;
let remoteConfig = null;
if (account && domain) try {
remoteConfig = await fetchPublishedConfig(account, domain);
if (remoteConfig) config = remoteConfig;
else return {
status: "error",
url: "",
error: `No config found at bos://${account}/${domain}. Verify the account and gateway are correct and the config has been published.\nExpected URL: ${require_fastkv.buildRegistryConfigUrl(account, domain)}`
};
} catch (error) {
return {
status: "error",
url: "",
error: `Failed to fetch config for bos://${account}/${domain}: ${error instanceof Error ? error.message : "Unknown error"}\nExpected URL: ${require_fastkv.buildRegistryConfigUrl(account, domain)}`
};
}
else config = deps.bosConfig;
if (!config) return {
status: "error",
url: "",
error: "No configuration found. Provide --account and --gateway flags, or create a local bos.config.json."
};
if (account) config = {
...config,
account
};
if (domain) config = {
...config,
domain
};
const port = input.port ?? require_config.getHostDevelopmentPort(config.app.host.development);
const isStaging = bosEnv === "staging";
const runtimePlugins = await require_config.buildRuntimePluginsForConfig(config, deps.configDir, "production");
require_config.suppressWarnings();
const runtimeConfig = require_app.buildRuntimeConfig(config, {
uiSource: "remote",
apiSource: "remote",
authSource: "remote",
hostSource: "remote",
env: "production",
plugins: runtimePlugins
});
require_config.drainConfigWarnings();
require_config.resumeWarnings();
if (isStaging && config.staging?.domain) runtimeConfig.domain = config.staging.domain;
if (isStaging) runtimeConfig.env = "staging";
require_infra.syncGeneratedInfra(deps.configDir, runtimeConfig);
require_infra.ensureEnvFile(deps.configDir);
require_infra.loadProjectEnv(deps.configDir);
pluginEvents.emit("progress", {
phase: "generate artifacts",
status: "running"
});
await require_code_artifacts.generateCodeArtifacts(deps.configDir, config, {
env: "production",
runtimeConfig
});
pluginEvents.emit("progress", {
phase: "generate artifacts",
status: "done"
});
const productionEnv = {};
const warnings = [];
if (!node_process.default.env.CORS_ORIGIN && config.domain) {
const defaultOrigin = `https://${isStaging ? config.staging?.domain ?? config.domain : config.domain}`;
productionEnv.CORS_ORIGIN = 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) requiredSecrets.add(s);
for (const secret of requiredSecrets) {
const value = node_process.default.env[secret];
if (!value || value.length === 0) missingSecrets.push(secret);
}
if (missingSecrets.length > 0) warnings.push(`Missing ${missingSecrets.length} secret(s): ${missingSecrets.join(", ")}`);
const services = require_service_descriptor.buildServiceDescriptorMap(runtimeConfig);
const stagingEnvVars = isStaging ? { BOS_GATEWAY: config.staging?.domain ?? config.domain ?? "" } : {};
const summary = {
configSource: remoteConfig ? `bos://${account}/${domain}` : require_config.findConfigPath() ?? "bos.config.json",
configSourceHttp: remoteConfig && account && domain ? require_fastkv.buildRegistryConfigUrl(account, domain) : void 0,
account: config.account,
domain: config.domain ?? void 0,
modules: {
host: runtimeConfig.host.remoteUrl ?? runtimeConfig.host.url ?? "local",
ui: runtimeConfig.ui.url ?? "local",
api: runtimeConfig.api.url ?? "local",
auth: runtimeConfig.auth?.url ?? void 0
},
warnings
};
pendingSession = {
orchestrator: {
packages: ["host"],
env: {
NODE_ENV: "production",
...productionEnv,
...stagingEnvVars
},
description: `${isStaging ? "Staging" : "Production"} Mode (${config.account})`,
port,
interactive: input.interactive,
noLogs: true
},
services,
runtimeConfig
};
pendingStartSummary = summary;
pluginEvents.emit("progress", {
phase: "config",
status: "done"
});
return {
status: "running",
url: `http://localhost:${port}`
};
}),
build: builder.build.handler(async ({ input }) => {
if (!deps.bosConfig) return {
status: "error",
built: [],
skipped: []
};
const buildEnv = input.deploy ? "production" : "development";
const targets = require_build.selectWorkspaceTargets(input.packages, deps.bosConfig);
if (targets.length === 0) return {
status: "error",
built: [],
skipped: []
};
require_config.suppressWarnings();
const runtimeConfig = require_app.buildRuntimeConfig(deps.bosConfig, {
uiSource: deps.bosConfig.app.ui?.development ? "local" : "remote",
apiSource: deps.bosConfig.app.api?.development ? "local" : "remote",
authSource: deps.bosConfig.app.auth?.development ? "local" : "remote",
hostSource: deps.bosConfig.app.host?.development ? "local" : "remote",
env: buildEnv,
plugins: deps.runtimeConfig?.plugins
});
require_config.drainConfigWarnings();
require_config.resumeWarnings();
await require_code_artifacts.generateCodeArtifacts(deps.configDir, deps.bosConfig, {
env: buildEnv,
runtimeConfig
});
const { built, skipped } = await require_build.buildWorkspaceTargets({
configDir: deps.configDir,
bosConfig: deps.bosConfig,
runtimeConfig,
targets,
deploy: input.deploy
});
if (built.length === 0) return {
status: "error",
built: [],
skipped
};
return {
status: "success",
built,
skipped,
deployed: input.deploy
};
}),
publish: builder.publish.handler(async ({ input }) => {
if (!deps.bosConfig) return {
status: "error",
registryUrl: "",
error: "No bos.config.json found"
};
const result = await require_publish.publishToFastKv({
bosConfig: deps.bosConfig,
runtimeConfig: deps.runtimeConfig,
configDir: deps.configDir,
env: input.env,
build: input.deploy,
dryRun: input.dryRun,
verbose: input.verbose,
packages: input.packages,
network: input.network,
privateKey: input.privateKey
});
if (result.publishConfig) {
const refreshed = await require_config.loadResolvedConfig({ cwd: deps.configDir });
if (refreshed?.config) {
deps.bosConfig = refreshed.config;
deps.runtimeConfig = refreshed.runtime;
}
}
return {
status: result.status,
registryUrl: result.registryUrl,
txHash: result.txHash,
error: result.error,
built: result.built,
skipped: result.skipped,
deployResults: result.deployResults
};
}),
deploy: builder.deploy.handler(async ({ input }) => {
if (!deps.bosConfig) return {
status: "error",
registryUrl: "",
redeployed: false,
error: "No bos.config.json found"
};
const result = await require_publish.publishToFastKv({
bosConfig: deps.bosConfig,
runtimeConfig: deps.runtimeConfig,
configDir: deps.configDir,
env: input.env,
build: input.build,
dryRun: input.dryRun,
verbose: input.verbose,
packages: input.packages,
network: input.network,
privateKey: input.privateKey
});
if (result.status === "error") return {
status: "error",
registryUrl: result.registryUrl,
txHash: result.txHash,
built: result.built,
skipped: result.skipped,
redeployed: false,
error: result.error,
deployResults: result.deployResults
};
if (result.status === "dry-run") return {
status: "dry-run",
registryUrl: result.registryUrl,
built: result.built,
skipped: result.skipped,
redeployed: false
};
if (result.publishConfig) {
const refreshed = await require_config.loadResolvedConfig({ cwd: deps.configDir });
if (refreshed?.config) {
deps.bosConfig = refreshed.config;
deps.runtimeConfig = refreshed.runtime;
}
}
let redeployed = false;
let service;
if (node_process.default.env.RAILWAY_TOKEN) {
const railwayService = input.service ?? deps.bosConfig.ci?.railway?.service;
if (!railwayService) {
console.log();
console.log(require_theme.colors.yellow(" Railway redeploy skipped: ci.railway.service is not configured in bos.config.json"));
return {
status: "published",
registryUrl: result.registryUrl,
txHash: result.txHash,
built: result.built,
skipped: result.skipped,
redeployed: false,
deployResults: result.deployResults,
error: "Config published but Railway redeploy failed: ci.railway.service is not configured in bos.config.json"
};
}
service = railwayService;
console.log();
console.log(` Redeploying Railway service ${require_theme.colors.cyan(railwayService)}...`);
try {
const railResult = await require_run.run("railway", [
"redeploy",
"--service",
railwayService,
"--yes"
], { capture: true });
if (railResult?.stdout) {
for (const line of railResult.stdout.split("\n")) if (line.trim()) console.log(` ${require_theme.colors.dim(line.trim())}`);
}
redeployed = true;
console.log(require_theme.colors.green(` Railway redeploy complete`));
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
const railError = message.includes("not found") || message.includes("ENOENT") ? "Railway CLI not found. Install it: npm i -g @railway/cli" : `Railway redeploy failed: ${message}`;
console.log(require_theme.colors.yellow(` ${railError}`));
return {
status: "published",
registryUrl: result.registryUrl,
txHash: result.txHash,
built: result.built,
skipped: result.skipped,
redeployed: false,
service,
deployResults: result.deployResults,
error: `Config published but ${railError}`
};
}
} else {
console.log();
console.log(require_theme.colors.yellow(" Railway redeploy skipped (RAILWAY_TOKEN not set)"));
}
return {
status: "deployed",
registryUrl: result.registryUrl,
txHash: result.txHash,
built: result.built,
skipped: result.skipped,
redeployed,
service,
deployResults: result.deployResults
};
}),
keyPublish: builder.keyPublish.handler(async ({ input }) => {
if (!deps.bosConfig) return {
status: "error",
account: "",
network: "mainnet",
contract: "",
allowance: input.allowance,
functionNames: PUBLISH_FUNCTION_NAMES,
error: "No bos.config.json found"
};
const account = deps.bosConfig.account;
const network = require_network.getNetworkIdForAccount(account);
const contract = require_fastkv.getRegistryNamespaceForAccount(account);
try {
await effect.Effect.runPromise(require_near_cli.ensureNearCli);
const keyPair = await require_near_cli.addFunctionCallAccessKey({
account,
contract,
allowance: input.allowance,
functionNames: PUBLISH_FUNCTION_NAMES,
network
});
return {
status: "published",
account,
network,
contract,
allowance: input.allowance,
functionNames: PUBLISH_FUNCTION_NAMES,
publicKey: keyPair.publicKey,
privateKey: keyPair.privateKey
};
} catch (error) {
return {
status: "error",
account,
network,
contract,
allowance: input.allowance,
functionNames: PUBLISH_FUNCTION_NAMES,
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
init: builder.init.handler(async ({ input }) => {
try {
const timings = [];
let extendsAccount = "";
let extendsGateway = "";
let directory = input.directory;
const account = input.account;
const domain = input.domain;
let overrides = input.overrides;
let plugins = input.plugins;
if (input.extends) {
const match = (input.extends.startsWith("bos://") ? input.extends : `bos://${input.extends}`).match(/^bos:\/\/([^/]+)\/(.+)$/);
if (match) {
extendsAccount = match[1];
extendsGateway = match[2];
}
}
extendsAccount = extendsAccount || "dev.everything.near";
extendsGateway = extendsGateway || "everything.dev";
let parentPluginKeys = [];
let parentConfig = null;
try {
parentConfig = await timePhase(timings, "parent config", () => require_cli_init.fetchParentConfig(extendsAccount, extendsGateway));
if (parentConfig?.plugins && typeof parentConfig.plugins === "object") parentPluginKeys = Object.keys(parentConfig.plugins);
} catch (e) {
console.warn(`[init] Failed to fetch parent config from ${extendsAccount}/${extendsGateway}: ${e instanceof Error ? e.message : e}`);
}
overrides = overrides?.length ? overrides : ["ui", "api"];
if (overrides.includes("plugins") && plugins === void 0) plugins = parentPluginKeys;
plugins = plugins ?? [];
const pluginDirMap = {};
if (parentConfig?.plugins) for (const plugin of plugins) {
const entry = parentConfig.plugins?.[plugin];
if (entry && typeof entry === "object") {
const dev = entry.development;
if (typeof dev === "string") {
const match = dev.match(/^local:plugins\/(.+)$/);
if (match?.[1] && match[1] !== plugin) pluginDirMap[plugin] = match[1];
}
}
}
directory = directory || domain || extendsGateway;
const targetDir = (0, node_path.resolve)(directory);
const extendsRef = `bos://${extendsAccount}/${extendsGateway}`;
const repository = await require_cli_init.detectGitRemoteUrl(node_process.default.cwd()).catch(() => void 0) ?? parentConfig?.repository;
if (!parentConfig) try {
parentConfig = await timePhase(timings, "parent config", () => require_cli_init.fetchParentConfig(extendsAccount, extendsGateway));
} catch {
return {
status: "error",
directory,
extendsRef,
account,
domain,
extends: extendsRef,
plugins,
overrides,
filesCopied: 0,
timings,
error: `No config found at ${extendsRef} — are you sure this is the right parent?`
};
}
const { sourceDir, parentConfig: resolvedParentConfig, cleanup } = await timePhase(timings, "template source", () => require_cli_init.resolveSourceDir({
extendsAccount,
extendsGateway,
source: input.source
}));
parentConfig = resolvedParentConfig;
const isMinimalScaffold = sourceDir === "";
try {
let filesCopied;
if (isMinimalScaffold) {
filesCopied = await timePhase(timings, "scaffold project", () => require_cli_init.scaffoldMinimalProject(targetDir, parentConfig, {
extendsAccount,
extendsGateway,
account: account || extendsAccount,
domain,
plugins,
overrides,
repository,
title: parentConfig?.title,
description: parentConfig?.description
}));
await timePhase(timings, "personalize config", () => require_cli_init.personalizeConfig(targetDir, {
extendsAccount,
extendsGateway,
account: account || extendsAccount,
domain: domain || extendsGateway,
plugins,
overrides,
mode: "init",
repository,
title: parentConfig?.title,
description: parentConfig?.description,
testnet: parentConfig?.testnet,
staging: parentConfig?.staging
}));
} else {
const patterns = require_cli_init.buildInitPatterns(overrides, plugins, pluginDirMap);
filesCopied = await timePhase(timings, "copy files", () => require_cli_init.copyFilteredFiles(sourceDir, targetDir, patterns, {
overrides,
plugins
}));
await timePhase(timings, "personalize config", () => require_cli_init.personalizeConfig(targetDir, {
extendsAccount,
extendsGateway,
account: account || extendsAccount,
domain: domain || extendsGateway,
plugins,
overrides,
workspaceOpts: { sourceDir },
repository,
title: parentConfig?.title,
description: parentConfig?.description,
testnet: parentConfig?.testnet,
staging: parentConfig?.staging
}));
await timePhase(timings, "write snapshot", () => require_cli_init.writeInitSnapshot(targetDir, extendsAccount, extendsGateway, sourceDir, patterns, {
overrides,
plugins
}));
await timePhase(timings, "personalize agents", () => require_cli_init.personalizeAgentsMd(targetDir, {
overrides,
plugins
}));
}
await timePhase(timings, "sync shared deps", () => require_shared_deps.syncResolvedSharedDeps({
configDir: targetDir,
hostMode: "local"
}));
const lockfilePath = (0, node_path.join)(targetDir, "bun.lock");
require_cli_init.stripOrphanedWorkspacesFromLockfile(lockfilePath, computeAllowedWorkspaces(overrides, plugins));
require_cli_init.removeInitLockfile(lockfilePath);
const initConfig = await timePhase(timings, "resolve config", () => require_config.loadResolvedConfig({ cwd: targetDir }));
if (initConfig?.runtime) await timePhase(timings, "generate env/docker", async () => {
require_infra.writeGeneratedInfra(targetDir, initConfig.runtime);
});
await timePhase(timings, "create env file", async () => {
require_infra.ensureEnvFile(targetDir);
});
if (!input.noInstall) {
await timePhase(timings, "install dependencies", () => require_cli_init.runBunInstall(targetDir));
await timePhase(timings, "generate types", () => require_cli_init.runTypesGen(targetDir));
await timePhase(timings, "generate migrations", () => require_cli_init.generateDatabaseMigrations(targetDir));
}
if (input.noInstall && initConfig?.config) await timePhase(timings, "generate code artifacts", () => require_code_artifacts.generateCodeArtifacts(targetDir, initConfig.config));
return {
status: "initialized",
directory,
extendsRef,
account,
domain,
extends: extendsRef,
plugins,
overrides,
filesCopied,
timings,
targetDir
};
} finally {
await cleanup();
}
} catch (error) {
const extendsRef = input.extends ? input.extends.startsWith("bos://") ? input.extends : `bos://${input.extends}` : "bos://dev.everything.near/everything.dev";
return {
status: "error",
directory: input.directory ?? "",
extendsRef,
account: input.account,
domain: input.domain,
extends: extendsRef,
plugins: input.plugins ?? [],
overrides: input.overrides,
filesCopied: 0,
timings: [],
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
sync: builder.sync.handler(async ({ input }) => {
try {
const configPath = require_config.findConfigPath();
if (!configPath) return {
status: "error",
updated: [],
skipped: [],
added: [],
error: "No bos.config.json found in current directory"
};
const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
const result = await require_sync.syncTemplate(projectDir, input);
if (result.status === "synced" || result.status === "dry-run") {
const syncedConfig = await require_config.loadResolvedConfig({ cwd: projectDir });
if (syncedConfig?.config) await require_code_artifacts.generateCodeArtifacts(projectDir, syncedConfig.config);
}
return result;
} catch (error) {
return {
status: "error",
updated: [],
skipped: [],
added: [],
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
upgrade: builder.upgrade.handler(async ({ input }) => {
try {
const configPath = require_config.findConfigPath();
if (!configPath) return {
status: "error",
packages: [],
error: "No bos.config.json found in current directory"
};
return await require_upgrade.upgradeTemplate((0, node_path.resolve)((0, node_path.dirname)(configPath)), input);
} catch (error) {
return {
status: "error",
packages: [],
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
typesGen: builder.typesGen.handler(async ({ input }) => {
try {
const configPath = require_config.findConfigPath();
if (!configPath) return {
status: "error",
generated: [],
fetched: [],
skipped: [],
failed: [],
error: "No bos.config.json found in current directory"
};
const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
const refreshed = await require_config.loadResolvedConfig({
cwd: projectDir,
env: input.env ?? (node_process.default.env.NODE_ENV === "production" ? "production" : "development")
});
if (!refreshed) return {
status: "error",
generated: [],
fetched: [],
skipped: [],
failed: [],
error: "Failed to load bos.config.json"
};
if (input.dryRun) {
const pluginEntries = Object.entries(refreshed.runtime.plugins ?? {});
const fetched = [];
const skipped = [];
const hasLocalApiWorkspace = (0, node_fs.existsSync)((0, node_path.join)(projectDir, "api", "src"));
if (refreshed.runtime.api.source !== "local") fetched.push(`api (${refreshed.runtime.api.url})`);
else skipped.push("api (local)");
if (refreshed.runtime.auth) if (refreshed.runtime.auth.source !== "local") fetched.push(`auth (${refreshed.runtime.auth.url})`);
else skipped.push("auth (local)");
for (const [key, plugin] of pluginEntries) if (plugin.url && plugin.source !== "local") fetched.push(`${key} (${plugin.url})`);
else if (plugin.localPath) skipped.push(`${key} (local)`);
else skipped.push(`${key} (no URL resolved)`);
const generated = ["ui/src/lib/api-types.gen.ts", "ui/src/lib/auth-types.gen.ts"];
if (hasLocalApiWorkspace) generated.push("api/src/lib/plugins-types.gen.ts", "api/src/lib/auth-types.gen.ts");
if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "src"))) generated.push("host/src/lib/auth-types.gen.ts");
return {
status: "success",
generated,
fetched,
skipped,
failed: [],
source: refreshed.runtime.api.source
};
}
const artifacts = await require_code_artifacts.generateCodeArtifacts(projectDir, refreshed.config, { runtimeConfig: refreshed.runtime });
const hasLocalApiWorkspace = (0, node_fs.existsSync)((0, node_path.join)(projectDir, "api", "src"));
const generated = ["ui/src/lib/api-types.gen.ts"];
if (hasLocalApiWorkspace) generated.push("api/src/lib/plugins-types.gen.ts", "api/src/lib/auth-types.gen.ts");
if (refreshed.runtime.auth && (refreshed.runtime.auth.source !== "local" || refreshed.runtime.auth.localPath)) generated.push("ui/src/lib/auth-types.gen.ts");
if ((0, node_fs.existsSync)((0, node_path.join)(projectDir, "host", "src"))) generated.push("host/src/lib/auth-types.gen.ts");
const contractStatus = artifacts?.contractStatus ?? [];
const fetched = [];
const skipped = [];
const failed = [];
for (const entry of contractStatus) if (entry.source === "remote") fetched.push(entry.url ? `${entry.key} (${entry.url})` : entry.key);
else if (entry.source === "local") skipped.push(`${entry.key} (local)`);
else if (entry.source === "skipped") skipped.push(`${entry.key} (no URL resolved)`);
else if (entry.source === "failed") {
const detail = entry.error ? `: ${entry.error}` : "";
failed.push(`${entry.key}${detail}`);
}
return {
status: "success",
generated,
fetched,
skipped,
failed,
source: refreshed.runtime.api.source
};
} catch (error) {
return {
status: "error",
generated: [],
fetched: [],
skipped: [],
failed: [],
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
dbStudio: builder.dbStudio.handler(async ({ input }) => {
try {
const configPath = require_config.findConfigPath();
if (!configPath) return {
status: "error",
plugin: input.plugin,
source: "remote",
section: "",
error: "No bos.config.json found in current directory"
};
const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
require_infra.loadProjectEnv(projectDir);
const refreshed = await require_config.loadResolvedConfig({ cwd: projectDir });
if (!refreshed) return {
status: "error",
plugin: input.plugin,
source: "remote",
section: "",
error: "Failed to load bos.config.json"
};
const { resolvePluginDbInfo } = await Promise.resolve().then(() => require("./cli/db-studio.cjs"));
const info = resolvePluginDbInfo(input.plugin, refreshed.runtime, projectDir);
return {
status: "success",
plugin: info.key,
source: info.source,
section: info.section,
databaseSecret: info.databaseSecret,
databaseUrl: info.databaseUrl,
workspaceDir: info.workspaceDir
};
} catch (error) {
return {
status: "error",
plugin: input.plugin,
source: "remote",
section: "",
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
status: builder.status.handler(async () => {
try {
const configPath = require_config.findConfigPath();
if (!configPath) return {
status: "error",
packages: [],
envFile: "missing",
error: "No bos.config.json found in current directory"
};
return await require_status.getStatus((0, node_path.resolve)((0, node_path.dirname)(configPath)));
} catch (error) {
return {
status: "error",
packages: [],
envFile: "missing",
error: error instanceof Error ? error.message : "Unknown error"
};
}
})
})
});
function computeAllowedWorkspaces(overrides, plugins) {
const workspaces = [];
for (const section of overrides) {
if (section === "host") workspaces.push("host");
if (section === "ui") workspaces.push("ui");
if (section === "api") workspaces.push("api");
}
if (plugins && plugins.length > 0) workspaces.push("plugins/*");
return workspaces;
}
//#endregion
exports.consumeDevSession = consumeDevSession;
exports.default = plugin_default;
exports.pluginEvents = pluginEvents;
exports.resolveRemoteConfigChain = resolveRemoteConfigChain;
//# sourceMappingURL=plugin.cjs.map