everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
83 lines (81 loc) • 2.8 kB
JavaScript
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { Effect } from "effect";
import { access } from "node:fs/promises";
import { homedir } from "node:os";
//#region src/process-registry.ts
function getRegistryDir() {
return join(homedir(), ".cache", "everything-dev");
}
function ensureRegistryDir() {
const dir = join(getRegistryPath(), "..");
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
}
function readRegistry() {
const path = getRegistryPath();
if (!existsSync(path)) return [];
try {
const raw = JSON.parse(readFileSync(path, "utf-8"));
if (!Array.isArray(raw)) return [];
return raw.filter((entry) => entry && typeof entry === "object" && typeof entry.pid === "number" && typeof entry.configDir === "string" && typeof entry.role === "string");
} catch {
return [];
}
}
function isPidAlive(pid) {
try {
process.kill(pid, 0);
return true;
} catch (err) {
return err.code !== "ESRCH";
}
}
function pruneDead(entries) {
return entries.filter((entry) => entry.pid > 1 && existsSync(entry.configDir) && isPidAlive(entry.pid));
}
function pruneDeadEffect(entries) {
return Effect.forEach(entries, (entry) => {
if (entry.pid <= 1) return Effect.succeed(null);
return Effect.gen(function* () {
if (!(yield* Effect.promise(() => access(entry.configDir).then(() => true).catch(() => false)))) return null;
if (!isPidAlive(entry.pid)) return null;
return entry;
});
}, { concurrency: "unbounded" }).pipe(Effect.map((results) => results.filter((e) => e !== null)));
}
function writeRegistry(entries) {
ensureRegistryDir();
const path = getRegistryPath();
const tmpPath = `${path}.tmp`;
writeFileSync(tmpPath, `${JSON.stringify(entries, null, 2)}\n`);
renameSync(tmpPath, path);
}
function registerStandalone(entry) {
const live = pruneDead(readRegistry());
const full = {
...entry,
role: "standalone"
};
const withoutSelf = live.filter((existing) => existing.pid !== entry.pid);
withoutSelf.push(full);
writeRegistry(withoutSelf);
return full;
}
function unregisterPid(pid) {
const live = pruneDead(readRegistry());
const next = live.filter((entry) => entry.pid !== pid);
if (next.length === live.length) return;
writeRegistry(next);
}
function getRegistryPath() {
return process.env.BO_PID_REGISTRY_PATH ?? join(getRegistryDir(), "pids.json");
}
function claimedPorts() {
const live = pruneDead(readRegistry());
const out = /* @__PURE__ */ new Set();
for (const entry of live) for (const port of Object.values(entry.ports)) if (typeof port === "number") out.add(port);
return out;
}
//#endregion
export { claimedPorts, pruneDeadEffect, readRegistry, registerStandalone, unregisterPid };
//# sourceMappingURL=process-registry.mjs.map