import { NextResponse } from "next/server"; import { getPaths } from "yt-dlp-transcript-common/lib/paths"; import { getSite, listSiteIds } from "yt-dlp-transcript-common/lib/site"; import { siteDeployProblem } from "yt-dlp-transcript-common/lib/builtExport"; import { enqueueAsks, lastJobOf, refusalsOf } from "../_publish"; import { OpsInputError, ops, optBool, optPreviewBranch, opsFail, reqSiteIds } from "../_lib"; export const dynamic = "force-dynamic"; // AN ALIAS (release 18): each site's build, then its deploy (the deploy waits on disk for that build). The body and the answer are the // route's old ones; the work is publish stages on the publish queue // (../_publish.ts), as `POST /api/ops/publish` {"verb": "build"} runs them. // // `all` = every DEPLOYABLE site to production (an explicit request: the // sites' policies are not asked); a private or project-less site is skipped // with its reason. → { ok, jobs: [{siteId, jobId, previewUrl?}], skipped } // with each site's DEPLOY job (the last of its run), as before. `all` used to // answer ONE job (build-deploy-all); it answers the per-site list now, and its // top-level `jobId` is the run's last job (`--wait` follows `jobs` anyway). export async function POST(request: Request) { return ops( request, ["siteId", "siteIds", "all", "skipArchives", "preview"], async (body) => { const skipArchives = optBool(body, "skipArchives"); const preview = optPreviewBranch(body); const paths = getPaths(); let ids: string[]; const skippedAll: { siteId: string; reason: string }[] = []; const all = optBool(body, "all") === true; if (all) { if (body.siteId !== undefined || body.siteIds !== undefined) { throw new OpsInputError('send either "siteId"/"siteIds" or "all", not both'); } if (preview !== undefined) { throw new OpsInputError( '"preview" is not supported with "all" — name the sites to preview with "siteIds"', ); } ids = []; for (const id of listSiteIds(paths)) { const site = getSite(id, paths); const why = siteDeployProblem(site) ?? (site.cloudflareProject ? null : "no cloudflareProject"); if (why) skippedAll.push({ siteId: id, reason: why }); else ids.push(id); } if (ids.length === 0) return opsFail("No deployable sites configured."); } else ids = reqSiteIds(body); const where = preview ? ("preview" as const) : ("production" as const); const run = await enqueueAsks( ids.map((target) => ({ target, build: { force: true, skipArchives }, deploy: { where, ...(preview ? { preview } : {}), force: true }, })), ); const jobs = ids.flatMap((siteId) => { const j = lastJobOf(run, siteId); return j ? [{ siteId, jobId: j.jobId, ...(j.previewUrl ? { previewUrl: j.previewUrl } : {}) }] : []; }); const skipped = [...skippedAll, ...refusalsOf(run).map((r) => ({ siteId: r.target, reason: r.error }))]; if (jobs.length === 0) { return opsFail(skipped.length === 1 ? skipped[0].reason : skipped.map((s) => `${s.siteId}: ${s.reason}`).join("; ")); } const lastOfRun = all ? run.jobs.at(-1)?.jobId : undefined; return NextResponse.json({ ok: true, runId: run.runId, jobs, skipped, ...(jobs.length === 1 ? { jobId: jobs[0].jobId, ...(jobs[0].previewUrl ? { previewUrl: jobs[0].previewUrl } : {}) } : lastOfRun ? { jobId: lastOfRun } : {}), }); }, ); } export function GET() { return NextResponse.json({ ok: false, error: "POST only" }, { status: 405 }); }