everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
199 lines (197 loc) • 7.76 kB
JavaScript
const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
const require_fastkv = require('../fastkv.cjs');
const require_config = require('../config.cjs');
const require_resolution_session = require('../resolution/session.cjs');
const require_fingerprint = require('../fingerprint.cjs');
const require_version_status = require('../version-status.cjs');
const require_shared = require('./shared.cjs');
const require_process_registry = require('../process-registry.cjs');
const require_app = require('../app.cjs');
const require_infra = require('../cli/infra.cjs');
const require_port_ownership = require('../infra/port-ownership.cjs');
const require_status = require('../cli/status.cjs');
const require_dev_logs = require('../dev-logs.cjs');
const require_process_kill = require('../process-kill.cjs');
let node_path = require("node:path");
let effect = require("effect");
let node_process = require("node:process");
node_process = require_runtime.__toESM(node_process, 1);
//#region src/commands/ops.ts
function registerOps(builder) {
return {
status: builder.status.handler(async ({ context }) => {
try {
const deps = effect.Context.get(context["effect/context"], require_shared.BosDepsTag);
const configPath = require_config.findConfigPath();
if (!configPath) return {
status: "error",
packages: [],
envFile: "missing",
error: `${require_config.MISSING_CONFIG_MESSAGE} in current directory`
};
const projectDir = (0, node_path.resolve)((0, node_path.dirname)(configPath));
return {
...await require_status.getStatus(projectDir),
deployedVersion: await deployedVersionStatus(deps)
};
} catch (error) {
return {
status: "error",
packages: [],
envFile: "missing",
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
logs: builder.logs.handler(async ({ input, context }) => {
try {
const configDir = effect.Context.get(context["effect/context"], require_shared.BosDepsTag).session?.root ?? node_process.default.cwd();
const text = await require_dev_logs.readDevLatestLog(configDir, { tail: input.tail });
const service = input.service;
const lines = text.split("\n").filter((line) => line.length > 0).filter((line) => {
if (!service) return true;
const match = /\] \[([^\]]+)\] \[(?:OUT|ERR)\] /.exec(line);
return match?.[1] === service || match?.[1] === `plugin:${service}`;
});
return {
logFile: require_dev_logs.resolveDevLatestFile(configDir),
lines
};
} catch (error) {
return {
logFile: "unknown",
lines: [error instanceof Error ? `Failed to read logs: ${error.message}` : "Failed to read logs"]
};
}
}),
ps: builder.ps.handler(async () => {
try {
return {
status: "ok",
entries: await effect.Effect.runPromise(require_process_registry.pruneDeadEffect(require_process_registry.readRegistry()))
};
} catch (error) {
return {
status: "error",
entries: [],
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
kill: builder.kill.handler(async ({ input }) => {
try {
const configPath = require_config.findConfigPath();
const targetConfigDir = input.all ? void 0 : input.configDir ?? (configPath ? (0, node_path.resolve)((0, node_path.dirname)(configPath)) : void 0);
const targets = targetConfigDir ? require_process_registry.readRegistry().filter((entry) => entry.configDir === targetConfigDir) : require_process_registry.readRegistry();
const killed = [];
const skipped = [];
for (const entry of targets) {
const wasAlive = require_process_registry.isPidAlive(entry.pid);
if (wasAlive) await effect.Effect.runPromise(require_process_kill.killProcessGroupEscalating(entry.pid, {
terminateMs: 5e3,
signal: input.signal === "SIGKILL" ? "SIGKILL" : "SIGTERM"
}));
const reapedChildren = [];
for (const childPid of entry.childPids ?? []) if (require_process_registry.isPidAlive(childPid)) {
require_process_kill.reapGroup(childPid);
reapedChildren.push(childPid);
}
const ports = Object.values(entry.ports ?? {}).filter((port) => Number.isFinite(port) && port > 0);
const stillBound = [];
for (const port of ports) {
let bindable = false;
for (let attempt = 0; attempt < 4; attempt++) {
bindable = await effect.Effect.runPromise(require_app.probePortBindable(port));
if (bindable) break;
await new Promise((resolve) => setTimeout(resolve, 500));
}
if (!bindable) stillBound.push(port);
}
if (stillBound.length > 0) {
const owner = await effect.Effect.runPromise(require_port_ownership.ownerOfPort(stillBound[0]));
skipped.push({
pid: entry.pid,
reason: `ports still bound after kill: ${stillBound.join(", ")}${owner ? ` — held by pid ${owner.pid} (${owner.command})` : " — owner unknown"}`
});
continue;
}
require_process_registry.unregisterPid(entry.pid);
killed.push({
pid: entry.pid,
configDir: entry.configDir
});
if (!wasAlive && reapedChildren.length > 0) skipped.push({
pid: entry.pid,
reason: `process already exited; reaped orphaned children ${reapedChildren.join(", ")}`
});
}
return {
status: "killed",
killed,
skipped
};
} catch (error) {
return {
status: "error",
killed: [],
skipped: [],
error: error instanceof Error ? error.message : "Unknown error"
};
}
}),
infraExport: builder.infraExport.handler(async ({ input, context }) => {
const deps = effect.Context.get(context["effect/context"], require_shared.BosDepsTag);
const configDir = input.configDir ?? deps.session?.root ?? node_process.default.cwd();
const ci = deps.session?.runtime ? require_infra.buildCiInfraPlan(deps.session.runtime) : null;
if (!ci) {
const refreshed = await require_resolution_session.openResolution({ cwd: configDir });
if (!refreshed?.runtime) throw new Error("No resolved runtime config available for infra export");
return require_infra.buildCiInfraPlan(refreshed.runtime);
}
return {
...ci,
account: deps.session?.config?.account ?? ci.account,
gateway: ci.gateway ?? deps.session?.config?.domain ?? deps.session?.config?.account ?? ci.account
};
})
};
}
async function deployedVersionStatus(deps) {
const config = deps.session?.config;
if (!config?.account || !config.domain) return void 0;
const { account, domain } = config;
let publishedFingerprint;
try {
const published = await require_fastkv.fetchBosConfigFromFastKv(`bos://${account}/${domain}`);
publishedFingerprint = require_fingerprint.pointerFingerprint(published);
} catch {
return;
}
const hostUrl = deps.session?.runtime?.host?.url;
if (!hostUrl) return require_version_status.computeDeployedVersionStatus({
publishedFingerprint,
servedFingerprint: null
});
try {
const response = await fetch(new URL("/.well-known/version", hostUrl));
if (!response.ok) return require_version_status.computeDeployedVersionStatus({
publishedFingerprint,
servedFingerprint: null,
servedError: `version endpoint returned ${response.status}`
});
const body = await response.json();
return require_version_status.computeDeployedVersionStatus({
publishedFingerprint,
servedFingerprint: body.fingerprint ?? null
});
} catch (error) {
return require_version_status.computeDeployedVersionStatus({
publishedFingerprint,
servedFingerprint: null,
servedError: error instanceof Error ? error.message : String(error)
});
}
}
//#endregion
exports.registerOps = registerOps;
//# sourceMappingURL=ops.cjs.map