Engineering manualAPI route source
/api/pulls
Exact current route handler: hosted-app/app/api/pulls/route.js
Methods: GET. Input signals: query parameters. Literal response-status signals: none detected.
Source: hosted-app/app/api/pulls/route.js. Imports: ../../../lib/comprehensive-pull.mjs, ../../../lib/pull-listing.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
// GET /api/pulls — every report this account has, newest first.
//
// The endpoint the launch review's deciding blocker needed and the product did
// not have. See hosted-app/lib/pull-listing.mjs for what a row may contain and
// why, and for the ownership rules; this file is the thin HTTP wrapper.
//
// Anonymous callers get the same 401 {signup_required} shape /api/credits and
// /api/comprehensive use, so the client's signed-out state is driven by the
// real gate rather than by a guess about whether a token exists.
import { NextResponse } from "next/server";
import { supabaseConfigFromEnv } from "../../../lib/supabase-rest.mjs";
import { bearerTokenFromHeader } from "../../../lib/comprehensive-pull.mjs";
import { listComprehensivePullsForUser, PULL_LIST_LIMIT } from "../../../lib/pull-listing.mjs";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
export async function GET(request) {
const token = bearerTokenFromHeader(request.headers.get("authorization"));
const config = supabaseConfigFromEnv(process.env);
const requested = Number(new URL(request.url).searchParams.get("limit"));
const limit = Number.isFinite(requested) && requested > 0 ? Math.min(PULL_LIST_LIMIT, requested) : PULL_LIST_LIMIT;
const result = await listComprehensivePullsForUser({ token, config, limit });
return NextResponse.json(result.body, { status: result.http_status });
}