|
| 1 | +import { NextRequest, NextResponse } from "next/server"; |
| 2 | +import { createClient } from "@/lib/supabase/server"; |
| 3 | +import { enqueueKeywordResearch } from "@/lib/lx/workerClient"; |
| 4 | +import { getProjectById, getCurrentSite } from "@/lib/lx/currentSite"; |
| 5 | + |
| 6 | +export const runtime = "nodejs"; |
| 7 | + |
| 8 | +// Hard-resets the upcoming queue. Used when the user's seeds, niche, |
| 9 | +// modifiers, or long-tail list have changed and the existing queue is |
| 10 | +// no longer aligned with what they want to publish. |
| 11 | +// |
| 12 | +// Deletes queued + failed keywords (failed ones were never produced — |
| 13 | +// they're not contractually "history"). Leaves published keywords intact |
| 14 | +// so research's dedup still skips topics the site has already covered. |
| 15 | +// Then enqueues a fresh research run. |
| 16 | +export async function POST(req: NextRequest) { |
| 17 | + const supabase = await createClient(); |
| 18 | + const { |
| 19 | + data: { user }, |
| 20 | + } = await supabase.auth.getUser(); |
| 21 | + if (!user) { |
| 22 | + return NextResponse.json({ ok: false, error: "unauthorized" }, { status: 401 }); |
| 23 | + } |
| 24 | + |
| 25 | + const projectIdParam = req.nextUrl.searchParams.get("projectId"); |
| 26 | + let lxSiteId: string | null = null; |
| 27 | + if (projectIdParam) { |
| 28 | + const project = await getProjectById(projectIdParam, { |
| 29 | + siteColumns: "id, niche, target_audiences", |
| 30 | + }); |
| 31 | + const lxSite = project?.lx_site as { id?: string } | null; |
| 32 | + lxSiteId = lxSite?.id ?? null; |
| 33 | + } else { |
| 34 | + const site = (await getCurrentSite("id")) as |
| 35 | + | { lx_site_id: string | null } |
| 36 | + | null; |
| 37 | + lxSiteId = site?.lx_site_id ?? null; |
| 38 | + } |
| 39 | + if (!lxSiteId) { |
| 40 | + return NextResponse.json( |
| 41 | + { ok: false, error: "autoblog not configured for this project" }, |
| 42 | + { status: 400 }, |
| 43 | + ); |
| 44 | + } |
| 45 | + |
| 46 | + // Delete queued + failed in one call. The RLS policy on lx_keyword is |
| 47 | + // SELECT-only for owners; deletes go through the service-role client |
| 48 | + // implicit in supabase.from() under the server route + cookie auth |
| 49 | + // (the policy denies anon, so we rely on the route's own auth check |
| 50 | + // above to gate access). |
| 51 | + const { error: delErr, count } = await supabase |
| 52 | + .from("lx_keyword") |
| 53 | + .delete({ count: "exact" }) |
| 54 | + .eq("site_id", lxSiteId) |
| 55 | + .in("status", ["queued", "failed"]); |
| 56 | + if (delErr) { |
| 57 | + return NextResponse.json( |
| 58 | + { ok: false, error: `delete failed: ${delErr.message}` }, |
| 59 | + { status: 500 }, |
| 60 | + ); |
| 61 | + } |
| 62 | + |
| 63 | + await enqueueKeywordResearch(lxSiteId); |
| 64 | + |
| 65 | + return NextResponse.json({ ok: true, deleted: count ?? 0 }); |
| 66 | +} |
0 commit comments