traceExport
uses node:crypto
Hand the server's traces to whoever holds its traces token (GET /__tcm/traces.sqlite, Authorization: Bearer <TCM_TRACES_TOKEN>): a copy of .tcm/data/traces.sqlite as it is now (gzipped, if asked for), which the studio
reads as production's. Without TCM_TRACES_TOKEN set, there's nothing there (404): a server's traces stay its own.
import type { Codebase } from "#codebase/tcmts/cli/codebase"; import type { Middleware } from "#codebase/tcmts/cli/web"; import { timingSafeEqual } from "node:crypto"; import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { DatabaseSync } from "node:sqlite"; import { createGzip } from "node:zlib"; export function traceExport(cb: Codebase): Middleware { return (req, res, next) => { if ((req.url ?? "").split("?")[0] !== "/__tcm/traces.sqlite") return next(); const answer = (status: number, text = "") => { res.statusCode = status; res.end(text); }; const token = process.env.TCM_TRACES_TOKEN; if (!token) return answer(404, "not found"); if (req.method !== "GET") return answer(405); const given = Buffer.from(/^Bearer (.+)$/.exec(req.headers.authorization ?? "")?.[1] ?? ""); const want = Buffer.from(token); if (given.length !== want.length || !timingSafeEqual(given, want)) return answer(401, "a traces token is needed"); const file = path.join(cb.lay.tcmDir, "data", "traces.sqlite"); if (!fs.existsSync(file)) return answer(204); // (a consistent copy, made apart from the tracer writing on: VACUUM INTO reads it as one transaction) const copy = path.join(fs.mkdtempSync(path.join(os.tmpdir(), "tcm-traces-")), "traces.sqlite"); const db = new DatabaseSync(file, { readOnly: true }); try { db.exec(`VACUUM INTO '${copy.replaceAll("'", "''")}'`); } catch { return answer(500, "the traces couldn't be read"); } finally { db.close(); } const gzip = /\bgzip\b/.test(String(req.headers["accept-encoding"] ?? "")); res.writeHead(200, { "content-type": "application/vnd.sqlite3", "cache-control": "no-store", ...(gzip ? { "content-encoding": "gzip" } : {}), }); const done = () => fs.rmSync(path.dirname(copy), { recursive: true, force: true }); const stream = fs.createReadStream(copy); stream.on("close", done); (gzip ? stream.pipe(createGzip()) : stream).pipe(res); }; }