UNPKG

everything-dev

Version:

A consolidated product package for building Module Federation apps with oRPC APIs.

1 lines 6.08 kB
{"version":3,"file":"process-registry.mjs","names":[],"sources":["../src/process-registry.ts"],"sourcesContent":["import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { Effect } from \"effect\";\n\nexport type ProcessRole = \"standalone\" | \"workspace-parent\" | \"workspace-child\";\n\nexport interface PidEntry {\n pid: number;\n configDir: string;\n parentPid?: number;\n role: ProcessRole;\n ports: Record<string, number>;\n budget?: { min: number; max: number };\n startedAt: number;\n description: string;\n}\n\nfunction getRegistryDir(): string {\n return join(homedir(), \".cache\", \"everything-dev\");\n}\n\nfunction ensureRegistryDir(): void {\n const path = getRegistryPath();\n const dir = join(path, \"..\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n}\n\nexport function readRegistry(): PidEntry[] {\n const path = getRegistryPath();\n if (!existsSync(path)) return [];\n try {\n const raw = JSON.parse(readFileSync(path, \"utf-8\"));\n if (!Array.isArray(raw)) return [];\n return raw.filter(\n (entry): entry is PidEntry =>\n entry &&\n typeof entry === \"object\" &&\n typeof entry.pid === \"number\" &&\n typeof entry.configDir === \"string\" &&\n typeof entry.role === \"string\",\n );\n } catch {\n return [];\n }\n}\n\nexport function isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code !== \"ESRCH\";\n }\n}\n\nexport function pruneDead(entries: PidEntry[]): PidEntry[] {\n return entries.filter(\n (entry) => entry.pid > 1 && existsSync(entry.configDir) && isPidAlive(entry.pid),\n );\n}\n\nexport function pruneDeadEffect(entries: PidEntry[]): Effect.Effect<PidEntry[]> {\n return Effect.forEach(\n entries,\n (entry) => {\n if (entry.pid <= 1) return Effect.succeed(null);\n return Effect.gen(function* () {\n const dirExists = yield* Effect.promise(() =>\n access(entry.configDir)\n .then(() => true)\n .catch(() => false),\n );\n if (!dirExists) return null;\n if (!isPidAlive(entry.pid)) return null;\n return entry;\n });\n },\n { concurrency: \"unbounded\" },\n ).pipe(Effect.map((results) => results.filter((e): e is PidEntry => e !== null)));\n}\n\nexport function writeRegistry(entries: PidEntry[]): void {\n ensureRegistryDir();\n const path = getRegistryPath();\n const tmpPath = `${path}.tmp`;\n writeFileSync(tmpPath, `${JSON.stringify(entries, null, 2)}\\n`);\n renameSync(tmpPath, path);\n}\n\nexport function registerStandalone(entry: Omit<PidEntry, \"role\">): PidEntry {\n const live = pruneDead(readRegistry());\n const full: PidEntry = { ...entry, role: \"standalone\" };\n const withoutSelf = live.filter((existing) => existing.pid !== entry.pid);\n withoutSelf.push(full);\n writeRegistry(withoutSelf);\n return full;\n}\n\nexport function registerEntry(entry: PidEntry): void {\n const live = pruneDead(readRegistry());\n const withoutSelf = live.filter((existing) => existing.pid !== entry.pid);\n withoutSelf.push(entry);\n writeRegistry(withoutSelf);\n}\n\nexport function unregisterPid(pid: number): void {\n const live = pruneDead(readRegistry());\n const next = live.filter((entry) => entry.pid !== pid);\n if (next.length === live.length) return;\n writeRegistry(next);\n}\n\nexport function removeRegistryFile(): void {\n const path = getRegistryPath();\n if (existsSync(path)) {\n rmSync(path, { force: true });\n }\n}\n\nexport function getRegistryPath(): string {\n return process.env.BO_PID_REGISTRY_PATH ?? join(getRegistryDir(), \"pids.json\");\n}\n\nexport function claimedPorts(): Set<number> {\n const live = pruneDead(readRegistry());\n const out = new Set<number>();\n for (const entry of live) {\n for (const port of Object.values(entry.ports)) {\n if (typeof port === \"number\") out.add(port);\n }\n }\n return out;\n}\n"],"mappings":";;;;;;;AAmBA,SAAS,iBAAyB;AAChC,QAAO,KAAK,SAAS,EAAE,UAAU,iBAAiB;;AAGpD,SAAS,oBAA0B;CAEjC,MAAM,MAAM,KADC,iBACQ,EAAE,KAAK;AAC5B,KAAI,CAAC,WAAW,IAAI,CAClB,WAAU,KAAK,EAAE,WAAW,MAAM,CAAC;;AAIvC,SAAgB,eAA2B;CACzC,MAAM,OAAO,iBAAiB;AAC9B,KAAI,CAAC,WAAW,KAAK,CAAE,QAAO,EAAE;AAChC,KAAI;EACF,MAAM,MAAM,KAAK,MAAM,aAAa,MAAM,QAAQ,CAAC;AACnD,MAAI,CAAC,MAAM,QAAQ,IAAI,CAAE,QAAO,EAAE;AAClC,SAAO,IAAI,QACR,UACC,SACA,OAAO,UAAU,YACjB,OAAO,MAAM,QAAQ,YACrB,OAAO,MAAM,cAAc,YAC3B,OAAO,MAAM,SAAS,SACzB;SACK;AACN,SAAO,EAAE;;;AAIb,SAAgB,WAAW,KAAsB;AAC/C,KAAI;AACF,UAAQ,KAAK,KAAK,EAAE;AACpB,SAAO;UACA,KAAK;AACZ,SAAQ,IAA8B,SAAS;;;AAInD,SAAgB,UAAU,SAAiC;AACzD,QAAO,QAAQ,QACZ,UAAU,MAAM,MAAM,KAAK,WAAW,MAAM,UAAU,IAAI,WAAW,MAAM,IAAI,CACjF;;AAGH,SAAgB,gBAAgB,SAAgD;AAC9E,QAAO,OAAO,QACZ,UACC,UAAU;AACT,MAAI,MAAM,OAAO,EAAG,QAAO,OAAO,QAAQ,KAAK;AAC/C,SAAO,OAAO,IAAI,aAAa;AAM7B,OAAI,EAAC,OALoB,OAAO,cAC9B,OAAO,MAAM,UAAU,CACpB,WAAW,KAAK,CAChB,YAAY,MAAM,CACtB,EACe,QAAO;AACvB,OAAI,CAAC,WAAW,MAAM,IAAI,CAAE,QAAO;AACnC,UAAO;IACP;IAEJ,EAAE,aAAa,aAAa,CAC7B,CAAC,KAAK,OAAO,KAAK,YAAY,QAAQ,QAAQ,MAAqB,MAAM,KAAK,CAAC,CAAC;;AAGnF,SAAgB,cAAc,SAA2B;AACvD,oBAAmB;CACnB,MAAM,OAAO,iBAAiB;CAC9B,MAAM,UAAU,GAAG,KAAK;AACxB,eAAc,SAAS,GAAG,KAAK,UAAU,SAAS,MAAM,EAAE,CAAC,IAAI;AAC/D,YAAW,SAAS,KAAK;;AAG3B,SAAgB,mBAAmB,OAAyC;CAC1E,MAAM,OAAO,UAAU,cAAc,CAAC;CACtC,MAAM,OAAiB;EAAE,GAAG;EAAO,MAAM;EAAc;CACvD,MAAM,cAAc,KAAK,QAAQ,aAAa,SAAS,QAAQ,MAAM,IAAI;AACzE,aAAY,KAAK,KAAK;AACtB,eAAc,YAAY;AAC1B,QAAO;;AAUT,SAAgB,cAAc,KAAmB;CAC/C,MAAM,OAAO,UAAU,cAAc,CAAC;CACtC,MAAM,OAAO,KAAK,QAAQ,UAAU,MAAM,QAAQ,IAAI;AACtD,KAAI,KAAK,WAAW,KAAK,OAAQ;AACjC,eAAc,KAAK;;AAUrB,SAAgB,kBAA0B;AACxC,QAAO,QAAQ,IAAI,wBAAwB,KAAK,gBAAgB,EAAE,YAAY;;AAGhF,SAAgB,eAA4B;CAC1C,MAAM,OAAO,UAAU,cAAc,CAAC;CACtC,MAAM,sBAAM,IAAI,KAAa;AAC7B,MAAK,MAAM,SAAS,KAClB,MAAK,MAAM,QAAQ,OAAO,OAAO,MAAM,MAAM,CAC3C,KAAI,OAAO,SAAS,SAAU,KAAI,IAAI,KAAK;AAG/C,QAAO"}