Engineering manualAPI route source
/api/brands/search-watch/sweep
Exact current route handler: hosted-app/app/api/brands/search-watch/sweep/route.js
Methods: GET, POST. Input signals: none detected. Literal response-status signals: 200.
Source: hosted-app/app/api/brands/search-watch/sweep/route.js. Imports: ../../../../../lib/monitoring-sweep.mjs, ../../../../../lib/search-watches.mjs, ../../../../../lib/social-watches.mjs, ../../../../../lib/supabase-rest.mjs, next/server. Exact source is shown for inspection; its presence does not prove authentication, validation or live behavior.
All API routes · API and execution contract
import { runMonitoringSweep } from "../../../../../lib/monitoring-sweep.mjs";
// /api/brands/search-watch/sweep — run the weekly search checks that are due.
//
// The self-hosted server runs the same sweep in-process (instrumentation.js);
// this route is for a platform scheduler or an operator. It uses the service
// role and can buy search snapshots for owners who approved them, so it fails
// closed: it needs the queue secret (x-queue-secret) or Vercel's CRON_SECRET
// bearer, and refuses outright when neither is configured. A check buys only
// when the provider's Google data is newer than the brand's latest snapshot,
// and one Google data date is never bought twice (lib/search-watches.mjs).
import { NextResponse } from "next/server";
import { supabaseConfigFromEnv } from "../../../../../lib/supabase-rest.mjs";
import { runDueSearchChecks } from "../../../../../lib/search-watches.mjs";
import { scheduledReportStarter } from "../../../../../lib/social-watches.mjs";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export const maxDuration = 60;
const authorizeSweep = (request, env) => {
const queueSecret = env.BRAND_STUDIO_QUEUE_SECRET || "";
const cronSecret = env.CRON_SECRET || "";
if (!queueSecret && !cronSecret) return { ok: false, http_status: 503, reason: "no_queue_secret_configured" };
const provided = request.headers.get("x-queue-secret") || "";
if (queueSecret && provided && provided === queueSecret) return { ok: true, via: "queue_secret" };
const authorization = request.headers.get("authorization") || "";
if (cronSecret && authorization === "Bearer " + cronSecret) return { ok: true, via: "vercel_cron" };
return { ok: false, http_status: 401, reason: "unauthorized" };
};
const sweep = async (request) => {
const env = process.env;
const auth = authorizeSweep(request, env);
const headers = { "cache-control": "no-store" };
if (!auth.ok) return NextResponse.json({ status: "refused", reason: auth.reason }, { status: auth.http_status, headers });
const config = supabaseConfigFromEnv(env);
const result = await runMonitoringSweep({ lane: "search", config, holder: "sweep-" + auth.via, run: () => env.BRAND_STUDIO_SEARCH_CHECKS === "off" ? ({ status: "skipped", reason: "checks_disabled" }) : runDueSearchChecks({ config, env, startReport: scheduledReportStarter({ config, env }), holder: "sweep-" + auth.via }) });
return NextResponse.json(result, { status: 200, headers });
};
export async function GET(request) { return sweep(request); }
export async function POST(request) { return sweep(request); }