UNPKG

everything-dev

Version:

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

1 lines • 13.3 kB
{"version":3,"file":"ops.cjs","names":["Context","BosDepsTag","findConfigPath","MISSING_CONFIG_MESSAGE","resolve","dirname","getStatus","process","readDevLatestLog","resolveDevLatestFile","Effect","pruneDeadEffect","readRegistry","isPidAlive","killProcessGroupEscalating","probePortBindable","ownerOfPort","buildCiInfraPlan","openResolution","fetchBosConfigFromFastKv","pointerFingerprint","computeDeployedVersionStatus"],"sources":["../../src/commands/ops.ts"],"sourcesContent":["import { dirname, resolve } from \"node:path\";\nimport process from \"node:process\";\nimport { Context, Effect } from \"effect\";\nimport { probePortBindable } from \"../app\";\nimport { buildCiInfraPlan, type CiInfraPlan } from \"../cli/infra\";\nimport { getStatus } from \"../cli/status\";\nimport { findConfigPath, MISSING_CONFIG_MESSAGE } from \"../config\";\nimport { readDevLatestLog, resolveDevLatestFile } from \"../dev-logs\";\nimport { fetchBosConfigFromFastKv } from \"../fastkv\";\nimport { pointerFingerprint } from \"../fingerprint\";\nimport { ownerOfPort } from \"../infra/port-ownership\";\nimport { killProcessGroupEscalating, reapGroup } from \"../process-kill\";\nimport { isPidAlive, pruneDeadEffect, readRegistry, unregisterPid } from \"../process-registry\";\nimport { openResolution } from \"../resolution/session\";\nimport { computeDeployedVersionStatus, type DeployedVersionStatus } from \"../version-status\";\nimport { type BosBuilder, type BosDeps, BosDepsTag } from \"./shared\";\n\nexport function registerOps(builder: BosBuilder) {\n return {\n status: builder.status.handler(async ({ context }) => {\n try {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const configPath = findConfigPath();\n if (!configPath) {\n return {\n status: \"error\" as const,\n packages: [],\n envFile: \"missing\" as const,\n error: `${MISSING_CONFIG_MESSAGE} in current directory`,\n };\n }\n\n const projectDir = resolve(dirname(configPath));\n const status = await getStatus(projectDir);\n return {\n ...status,\n deployedVersion: await deployedVersionStatus(deps),\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n packages: [],\n envFile: \"missing\" as const,\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n\n logs: builder.logs.handler(async ({ input, context }) => {\n try {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const configDir = deps.session?.root ?? process.cwd();\n const text = await readDevLatestLog(configDir, { tail: input.tail });\n const service = input.service;\n const lines = text\n .split(\"\\n\")\n .filter((line) => line.length > 0)\n .filter((line) => {\n if (!service) return true;\n const match = /\\] \\[([^\\]]+)\\] \\[(?:OUT|ERR)\\] /.exec(line);\n return match?.[1] === service || match?.[1] === `plugin:${service}`;\n });\n return {\n logFile: resolveDevLatestFile(configDir),\n lines,\n };\n } catch (error) {\n return {\n logFile: \"unknown\",\n lines: [\n error instanceof Error\n ? `Failed to read logs: ${error.message}`\n : \"Failed to read logs\",\n ],\n };\n }\n }),\n\n ps: builder.ps.handler(async () => {\n try {\n const entries = await Effect.runPromise(pruneDeadEffect(readRegistry()));\n return {\n status: \"ok\" as const,\n entries,\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n entries: [],\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n\n kill: builder.kill.handler(async ({ input }) => {\n try {\n const configPath = findConfigPath();\n const targetConfigDir = input.all\n ? undefined\n : (input.configDir ?? (configPath ? resolve(dirname(configPath)) : undefined));\n\n const targets = targetConfigDir\n ? readRegistry().filter((entry) => entry.configDir === targetConfigDir)\n : readRegistry();\n\n const killed: Array<{ pid: number; configDir: string }> = [];\n const skipped: Array<{ pid: number; reason: string }> = [];\n\n for (const entry of targets) {\n const wasAlive = isPidAlive(entry.pid);\n if (wasAlive) {\n await Effect.runPromise(\n killProcessGroupEscalating(entry.pid, {\n terminateMs: 5000,\n signal: input.signal === \"SIGKILL\" ? \"SIGKILL\" : \"SIGTERM\",\n }),\n );\n }\n\n const reapedChildren: number[] = [];\n for (const childPid of entry.childPids ?? []) {\n if (isPidAlive(childPid)) {\n reapGroup(childPid);\n reapedChildren.push(childPid);\n }\n }\n\n const ports = Object.values(entry.ports ?? {}).filter(\n (port) => Number.isFinite(port) && port > 0,\n );\n const stillBound: number[] = [];\n for (const port of ports) {\n let bindable = false;\n for (let attempt = 0; attempt < 4; attempt++) {\n bindable = await Effect.runPromise(probePortBindable(port));\n if (bindable) break;\n await new Promise((resolve) => setTimeout(resolve, 500));\n }\n if (!bindable) stillBound.push(port);\n }\n\n if (stillBound.length > 0) {\n const owner = await Effect.runPromise(ownerOfPort(stillBound[0]));\n skipped.push({\n pid: entry.pid,\n reason: `ports still bound after kill: ${stillBound.join(\", \")}${\n owner ? ` — held by pid ${owner.pid} (${owner.command})` : \" — owner unknown\"\n }`,\n });\n continue;\n }\n\n unregisterPid(entry.pid);\n killed.push({ pid: entry.pid, configDir: entry.configDir });\n if (!wasAlive && reapedChildren.length > 0) {\n skipped.push({\n pid: entry.pid,\n reason: `process already exited; reaped orphaned children ${reapedChildren.join(\", \")}`,\n });\n }\n }\n\n return {\n status: \"killed\" as const,\n killed,\n skipped,\n };\n } catch (error) {\n return {\n status: \"error\" as const,\n killed: [],\n skipped: [],\n error: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }),\n\n infraExport: builder.infraExport.handler(async ({ input, context }) => {\n const deps = Context.get(context[\"effect/context\"], BosDepsTag);\n const configDir = input.configDir ?? deps.session?.root ?? process.cwd();\n const ci = deps.session?.runtime ? buildCiInfraPlan(deps.session.runtime) : null;\n if (!ci) {\n const refreshed = await openResolution({ cwd: configDir });\n if (!refreshed?.runtime) {\n throw new Error(\"No resolved runtime config available for infra export\");\n }\n return buildCiInfraPlan(refreshed.runtime);\n }\n const result: CiInfraPlan & { account: string; gateway: string } = {\n ...ci,\n account: deps.session?.config?.account ?? ci.account,\n gateway:\n ci.gateway ?? deps.session?.config?.domain ?? deps.session?.config?.account ?? ci.account,\n };\n return result;\n }),\n };\n}\n\nasync function deployedVersionStatus(deps: BosDeps): Promise<DeployedVersionStatus | undefined> {\n const config = deps.session?.config;\n if (!config?.account || !config.domain) return undefined;\n const { account, domain } = config;\n let publishedFingerprint: string | undefined;\n try {\n const published = await fetchBosConfigFromFastKv<Record<string, unknown>>(\n `bos://${account}/${domain}`,\n );\n publishedFingerprint = pointerFingerprint(published as never);\n } catch {\n return undefined;\n }\n\n const hostUrl = deps.session?.runtime?.host?.url;\n if (!hostUrl) {\n return computeDeployedVersionStatus({ publishedFingerprint, servedFingerprint: null });\n }\n try {\n const response = await fetch(new URL(\"/.well-known/version\", hostUrl));\n if (!response.ok) {\n return computeDeployedVersionStatus({\n publishedFingerprint,\n servedFingerprint: null,\n servedError: `version endpoint returned ${response.status}`,\n });\n }\n const body = (await response.json()) as { fingerprint?: string };\n return computeDeployedVersionStatus({\n publishedFingerprint,\n servedFingerprint: body.fingerprint ?? null,\n });\n } catch (error) {\n return computeDeployedVersionStatus({\n publishedFingerprint,\n servedFingerprint: null,\n servedError: error instanceof Error ? error.message : String(error),\n });\n }\n}\n"],"mappings":"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"}