runRegistry
uses node:path
Runs tcm registry, without opening a codebase: the registry tcm ships (registry), copied into --dir (again when tcm's
changes) and run there by tcm start, its jobs with it, until it's stopped. The codebase it mirrors libraries into
(.tcm/data/registry, or hub; TCM_REGISTRY_CODEBASE), made by an older tcm, is moved to this one's layout and
hash format first, as tcm migrate does (kept as it was beside it).
import { routeRegistry } from "#codebase/tcmts/cli/commands"; import { execute } from "#codebase/tcmts/cli/main"; import { migrateCodebase, migrateCopy } from "#codebase/tcmts/cli/migrate"; import { SHIPPED_APP } from "#codebase/tcmts/cli/pack"; import { registryEnv } from "#codebase/tcmts/cli/run"; import type { Started } from "#codebase/tcmts/cli/run"; import { dim } from "#codebase/tcmts/cli/style"; import { shippedApp } from "#codebase/tcmts/cli/sync"; import { UsageError } from "#codebase/tcmts/cli/ui"; import { parse } from "@bomb.sh/router"; import { spawn } from "node:child_process"; import { createHash } from "node:crypto"; import fs from "node:fs"; import path from "node:path"; export async function runRegistry({ cmd, rest, cwd }: Started): Promise<number> { const m = execute(cmd, parse(routeRegistry(), { argv: rest })).model; const shipped = shippedApp("registry"); if (!shipped) throw new UsageError( "this tcm doesn't ship the registry: a tcm installed from its package does", ); const base = m.base?.replace(/\/+$/, ""); if (base !== undefined && !/^\/[^\s?#]+$/.test(base)) throw new UsageError(`--base ${m.base}: the path it's served under, as /registry`); const dir = path.resolve(cwd, m.dir); const from = path.join(shipped, "codebase.sqlite"); const to = path.join(dir, ".tcm", "codebase.sqlite"); const digest = createHash("sha256").update(fs.readFileSync(from)).digest("hex"); const mark = path.join(dir, ".tcm", "shipped"); if (fs.existsSync(path.join(dir, ".tcm")) && !fs.existsSync(mark)) throw new UsageError(`${dir} holds a codebase that isn't a registry: give another --dir`); if (!fs.existsSync(to) || fs.readFileSync(mark, "utf8") !== digest) { fs.mkdirSync(path.dirname(to), { recursive: true }); for (const f of [to, `${to}-wal`, `${to}-shm`]) fs.rmSync(f, { force: true }); fs.copyFileSync(from, to); fs.writeFileSync(mark, digest); } // (an older tcm may have packed it, or copied it here) migrateCopy(to); // (and the codebase it mirrors into, as registryDir finds it: an older tcm's, read by none of this one's pages) const data = path.join(dir, ".tcm", "data"); const mirror = [ process.env.TCM_REGISTRY_CODEBASE, path.join(data, "hub"), path.join(data, "registry"), ].find((d) => d && fs.existsSync(path.join(d, ".tcm", "codebase.sqlite"))); if (mirror) { const done = migrateCodebase(mirror); if (done) console.log( dim(`registry: its codebase moved to this tcm's layout; as it was: ${done.backup}`), ); } // (it stops when this does, however this ends) const env = registryEnv(process.env); const child = spawn( process.execPath, // (and its HTTP routes, under /api: its OAuth client metadata, for visitors signing in on a domain, and search; // all of it under the base, if it has one) [ process.argv[1]!, "start", SHIPPED_APP, "--port", String(m.port), "--host", m.host, "--http", "http=/api", ...(base ? ["--base", base] : []), ], { cwd: dir, env, stdio: "inherit" }, ); const stop = () => child.kill(); process.once("SIGINT", stop); process.once("SIGTERM", stop); return new Promise((resolve) => child.on("exit", (code) => resolve(code ?? 0))); }
uses
- tcmts.cli.commands.routeRegistry
- tcmts.cli.main.execute
- tcmts.cli.migrate.migrateCodebase
- tcmts.cli.migrate.migrateCopy
- tcmts.cli.pack.SHIPPED_APP
- tcmts.cli.run.Started
- tcmts.cli.run.registryEnv
- tcmts.cli.style.dim
- tcmts.cli.sync.shippedApp
- tcmts.cli.ui.UsageError