Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions app/api/research/albums/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchAlbumsHandler } from "@/lib/research/getResearchAlbumsHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchAlbumsHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/audience/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchAudienceHandler } from "@/lib/research/getResearchAudienceHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchAudienceHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/career/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchCareerHandler } from "@/lib/research/getResearchCareerHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchCareerHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/charts/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchChartsHandler } from "@/lib/research/getResearchChartsHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchChartsHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/cities/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchCitiesHandler } from "@/lib/research/getResearchCitiesHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchCitiesHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/curator/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchCuratorHandler } from "@/lib/research/getResearchCuratorHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchCuratorHandler(request);
}
19 changes: 19 additions & 0 deletions app/api/research/deep/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { postResearchDeepHandler } from "@/lib/research/postResearchDeepHandler";

/**
* OPTIONS handler for CORS preflight requests.
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
* POST /api/research/deep
*
* Deep, comprehensive research with citations.
*/
export async function POST(request: NextRequest) {
return postResearchDeepHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/discover/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchDiscoverHandler } from "@/lib/research/getResearchDiscoverHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchDiscoverHandler(request);
}
Comment on lines +1 to +18
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate route and handler symbols
fd --type f 'route.ts' app/api/research | sort
rg -n 'getResearchDiscoverHandler|/api/research/discover'

# Find tests referencing discover endpoint/handler
rg -n --iglob '*{test,spec}*.{ts,tsx,js,jsx}' \
  '/api/research/discover|getResearchDiscoverHandler'

# Check for explicit error-path assertions (status codes/messages)
rg -n --iglob '*{test,spec}*.{ts,tsx,js,jsx}' \
  'discover.*(400|401|402|500)|status\s*[:=]\s*(400|401|402|500)|insufficient|invalid|missing'

Repository: recoupable/api

Length of output: 1160


🏁 Script executed:

cat -n lib/research/getResearchDiscoverHandler.ts

Repository: recoupable/api

Length of output: 2924


Add comprehensive test coverage and implement Zod query validation for this endpoint.

Missing test coverage for success and error paths (credit insufficiency, auth failure, proxy failures). Additionally, query parameters should be validated using a Zod schema (validateDiscoverQuery.ts) rather than manually parsed. The route file's JSDoc comments are empty and should document the endpoint's parameters and behavior.

The handler correctly uses validateAuthContext() and includes proper error handling, but these should be covered by tests. Create:

  • Tests covering auth success/failure, credit success/failure, and proxy success/failure paths
  • A lib/research/validateDiscoverQuery.ts file exporting a Zod schema and inferred type for country, genre, sort, limit, sp_monthly_listeners_min, sp_monthly_listeners_max parameters
  • JSDoc comments in the route file documenting the endpoint
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/research/discover/route.ts` around lines 1 - 18, Add Zod-based query
validation and comprehensive tests: create lib/research/validateDiscoverQuery.ts
exporting a Zod schema and inferred TypeScript type for the query params
(country, genre, sort, limit, sp_monthly_listeners_min,
sp_monthly_listeners_max) and update the discover handler to use that schema
instead of manual parsing (reference getResearchDiscoverHandler and the exported
schema name). Add JSDoc to the route file (the exported OPTIONS and GET
handlers) documenting accepted query parameters, auth requirements, and possible
responses. Add tests that exercise success and error paths for auth
(validateAuthContext), credit checks, and proxy failures by invoking the GET
route or directly calling getResearchDiscoverHandler with mocked dependencies,
and include tests validating the schema rejectsbad inputs and accepts valid
ones.

19 changes: 19 additions & 0 deletions app/api/research/enrich/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { postResearchEnrichHandler } from "@/lib/research/postResearchEnrichHandler";

/**
* OPTIONS handler for CORS preflight requests.
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
* POST /api/research/enrich
*
* Enrich an entity with structured web research data.
*/
export async function POST(request: NextRequest) {
return postResearchEnrichHandler(request);
}
19 changes: 19 additions & 0 deletions app/api/research/extract/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { postResearchExtractHandler } from "@/lib/research/postResearchExtractHandler";

/**
* OPTIONS handler for CORS preflight requests.
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
* POST /api/research/extract
*
* Extract clean markdown from URLs.
*/
export async function POST(request: NextRequest) {
return postResearchExtractHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/festivals/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchFestivalsHandler } from "@/lib/research/getResearchFestivalsHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchFestivalsHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/genres/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchGenresHandler } from "@/lib/research/getResearchGenresHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchGenresHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/insights/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchInsightsHandler } from "@/lib/research/getResearchInsightsHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchInsightsHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/instagram-posts/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchInstagramPostsHandler } from "@/lib/research/getResearchInstagramPostsHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchInstagramPostsHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/lookup/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchLookupHandler } from "@/lib/research/getResearchLookupHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchLookupHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/metrics/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchMetricsHandler } from "@/lib/research/getResearchMetricsHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchMetricsHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/milestones/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchMilestonesHandler } from "@/lib/research/getResearchMilestonesHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchMilestonesHandler(request);
}
19 changes: 19 additions & 0 deletions app/api/research/people/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { postResearchPeopleHandler } from "@/lib/research/postResearchPeopleHandler";

/**
* OPTIONS handler for CORS preflight requests.
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
* POST /api/research/people
*
* Search for people in the music industry.
*/
export async function POST(request: NextRequest) {
return postResearchPeopleHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/playlist/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchPlaylistHandler } from "@/lib/research/getResearchPlaylistHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchPlaylistHandler(request);
}
18 changes: 18 additions & 0 deletions app/api/research/playlists/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextRequest, NextResponse } from "next/server";
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
import { getResearchPlaylistsHandler } from "@/lib/research/getResearchPlaylistsHandler";

/**
*
*/
export async function OPTIONS() {
return new NextResponse(null, { status: 200, headers: getCorsHeaders() });
}

/**
*
* @param request
*/
export async function GET(request: NextRequest) {
return getResearchPlaylistsHandler(request);
}
Loading
Loading