Skip to content

Commit d673a22

Browse files
committed
Merge branch 'test'
2 parents ee8aeaf + 153cd2d commit d673a22

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2493
-13
lines changed

app/api/content/analyze/route.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
3+
import { createAnalyzeHandler } from "@/lib/content/analyze/createAnalyzeHandler";
4+
5+
/**
6+
* OPTIONS handler for CORS preflight requests.
7+
*/
8+
export async function OPTIONS() {
9+
return new NextResponse(null, { status: 204, headers: getCorsHeaders() });
10+
}
11+
12+
/**
13+
* POST /api/content/analyze
14+
*
15+
* Analyze a video with AI — describe scenes, check quality, evaluate content.
16+
*/
17+
export async function POST(request: NextRequest): Promise<NextResponse> {
18+
return createAnalyzeHandler(request);
19+
}
20+
21+
export const dynamic = "force-dynamic";
22+
export const fetchCache = "force-no-store";
23+
export const revalidate = 0;

app/api/content/caption/route.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
3+
import { createTextHandler } from "@/lib/content/caption/createTextHandler";
4+
5+
/**
6+
* OPTIONS handler for CORS preflight requests.
7+
*/
8+
export async function OPTIONS() {
9+
return new NextResponse(null, { status: 204, headers: getCorsHeaders() });
10+
}
11+
12+
/**
13+
* POST /api/content/caption
14+
*
15+
* Generate on-screen caption text for a social video.
16+
*/
17+
export async function POST(request: NextRequest): Promise<NextResponse> {
18+
return createTextHandler(request);
19+
}
20+
21+
export const dynamic = "force-dynamic";
22+
export const fetchCache = "force-no-store";
23+
export const revalidate = 0;

app/api/content/image/route.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
3+
import { createImageHandler } from "@/lib/content/image/createImageHandler";
4+
5+
/**
6+
* OPTIONS handler for CORS preflight requests.
7+
*/
8+
export async function OPTIONS() {
9+
return new NextResponse(null, { status: 204, headers: getCorsHeaders() });
10+
}
11+
12+
/**
13+
* POST /api/content/image
14+
*
15+
* Generate an image from a prompt and optional reference image.
16+
*/
17+
export async function POST(request: NextRequest): Promise<NextResponse> {
18+
return createImageHandler(request);
19+
}
20+
21+
export const dynamic = "force-dynamic";
22+
export const fetchCache = "force-no-store";
23+
export const revalidate = 0;

app/api/content/route.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
3+
import { editHandler } from "@/lib/content/edit/editHandler";
4+
5+
/**
6+
* OPTIONS handler for CORS preflight requests.
7+
*/
8+
export async function OPTIONS() {
9+
return new NextResponse(null, { status: 204, headers: getCorsHeaders() });
10+
}
11+
12+
/**
13+
* PATCH /api/content
14+
*
15+
* Edit media with operations or a template preset.
16+
*/
17+
export async function PATCH(request: NextRequest): Promise<NextResponse> {
18+
return editHandler(request);
19+
}
20+
21+
export const dynamic = "force-dynamic";
22+
export const fetchCache = "force-no-store";
23+
export const revalidate = 0;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
3+
import { getContentTemplateDetailHandler } from "@/lib/content/getContentTemplateDetailHandler";
4+
5+
/**
6+
* OPTIONS handler for CORS preflight requests.
7+
*/
8+
export async function OPTIONS() {
9+
return new NextResponse(null, { status: 204, headers: getCorsHeaders() });
10+
}
11+
12+
/**
13+
* GET /api/content/templates/[id]
14+
*
15+
* Returns the full template configuration for a given template id.
16+
*/
17+
export async function GET(
18+
request: NextRequest,
19+
context: { params: Promise<{ id: string }> },
20+
): Promise<NextResponse> {
21+
return getContentTemplateDetailHandler(request, context);
22+
}
23+
24+
export const dynamic = "force-dynamic";
25+
export const fetchCache = "force-no-store";
26+
export const revalidate = 0;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
3+
import { createAudioHandler } from "@/lib/content/transcribe/createAudioHandler";
4+
5+
/**
6+
* OPTIONS handler for CORS preflight requests.
7+
*/
8+
export async function OPTIONS() {
9+
return new NextResponse(null, { status: 204, headers: getCorsHeaders() });
10+
}
11+
12+
/**
13+
* POST /api/content/transcribe
14+
*
15+
* Transcribe audio into text with word-level timestamps.
16+
*/
17+
export async function POST(request: NextRequest): Promise<NextResponse> {
18+
return createAudioHandler(request);
19+
}
20+
21+
export const dynamic = "force-dynamic";
22+
export const fetchCache = "force-no-store";
23+
export const revalidate = 0;

app/api/content/upscale/route.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
3+
import { createUpscaleHandler } from "@/lib/content/upscale/createUpscaleHandler";
4+
5+
/**
6+
* OPTIONS handler for CORS preflight requests.
7+
*/
8+
export async function OPTIONS() {
9+
return new NextResponse(null, { status: 204, headers: getCorsHeaders() });
10+
}
11+
12+
/**
13+
* POST /api/content/upscale
14+
*
15+
* Upscale an image or video to higher resolution.
16+
*/
17+
export async function POST(request: NextRequest): Promise<NextResponse> {
18+
return createUpscaleHandler(request);
19+
}
20+
21+
export const dynamic = "force-dynamic";
22+
export const fetchCache = "force-no-store";
23+
export const revalidate = 0;

app/api/content/video/route.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { NextRequest, NextResponse } from "next/server";
2+
import { getCorsHeaders } from "@/lib/networking/getCorsHeaders";
3+
import { createVideoHandler } from "@/lib/content/video/createVideoHandler";
4+
5+
/**
6+
* OPTIONS handler for CORS preflight requests.
7+
*/
8+
export async function OPTIONS() {
9+
return new NextResponse(null, { status: 204, headers: getCorsHeaders() });
10+
}
11+
12+
/**
13+
* POST /api/content/video
14+
*
15+
* Generate a video from a prompt, image, or existing video.
16+
*/
17+
export async function POST(request: NextRequest): Promise<NextResponse> {
18+
return createVideoHandler(request);
19+
}
20+
21+
export const dynamic = "force-dynamic";
22+
export const fetchCache = "force-no-store";
23+
export const revalidate = 0;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
import { NextRequest, NextResponse } from "next/server";
3+
import { getContentTemplateDetailHandler } from "@/lib/content/getContentTemplateDetailHandler";
4+
import { validateAuthContext } from "@/lib/auth/validateAuthContext";
5+
import { loadTemplate } from "@/lib/content/templates";
6+
7+
vi.mock("@/lib/networking/getCorsHeaders", () => ({
8+
getCorsHeaders: vi.fn(() => ({ "Access-Control-Allow-Origin": "*" })),
9+
}));
10+
11+
vi.mock("@/lib/auth/validateAuthContext", () => ({
12+
validateAuthContext: vi.fn(),
13+
}));
14+
15+
vi.mock("@/lib/content/templates", () => ({
16+
loadTemplate: vi.fn(),
17+
}));
18+
19+
describe("getContentTemplateDetailHandler", () => {
20+
beforeEach(() => {
21+
vi.clearAllMocks();
22+
});
23+
24+
it("returns 401 when not authenticated", async () => {
25+
vi.mocked(validateAuthContext).mockResolvedValue(
26+
NextResponse.json({ status: "error", error: "Unauthorized" }, { status: 401 }),
27+
);
28+
const request = new NextRequest("http://localhost/api/content/templates/bedroom", {
29+
method: "GET",
30+
});
31+
32+
const result = await getContentTemplateDetailHandler(request, {
33+
params: Promise.resolve({ id: "bedroom" }),
34+
});
35+
36+
expect(result.status).toBe(401);
37+
});
38+
39+
it("returns 404 for unknown template", async () => {
40+
vi.mocked(validateAuthContext).mockResolvedValue({
41+
accountId: "acc_123",
42+
orgId: null,
43+
authToken: "test-key",
44+
});
45+
vi.mocked(loadTemplate).mockReturnValue(null);
46+
47+
const request = new NextRequest("http://localhost/api/content/templates/nonexistent", {
48+
method: "GET",
49+
});
50+
51+
const result = await getContentTemplateDetailHandler(request, {
52+
params: Promise.resolve({ id: "nonexistent" }),
53+
});
54+
const body = await result.json();
55+
56+
expect(result.status).toBe(404);
57+
expect(body.error).toBe("Template not found");
58+
});
59+
60+
it("returns full template for valid id", async () => {
61+
vi.mocked(validateAuthContext).mockResolvedValue({
62+
accountId: "acc_123",
63+
orgId: null,
64+
authToken: "test-key",
65+
});
66+
const mockTemplate = {
67+
id: "artist-caption-bedroom",
68+
description: "Moody purple bedroom setting",
69+
image: { prompt: "test", reference_images: [], style_rules: {} },
70+
video: { moods: ["calm"], movements: ["slow pan"] },
71+
caption: { guide: { tone: "dreamy", rules: [], formats: [] }, examples: [] },
72+
edit: { operations: [] },
73+
};
74+
vi.mocked(loadTemplate).mockReturnValue(mockTemplate);
75+
76+
const request = new NextRequest(
77+
"http://localhost/api/content/templates/artist-caption-bedroom",
78+
{ method: "GET" },
79+
);
80+
81+
const result = await getContentTemplateDetailHandler(request, {
82+
params: Promise.resolve({ id: "artist-caption-bedroom" }),
83+
});
84+
const body = await result.json();
85+
86+
expect(result.status).toBe(200);
87+
expect(body.id).toBe("artist-caption-bedroom");
88+
expect(body.description).toBe("Moody purple bedroom setting");
89+
expect(body.image).toBeDefined();
90+
expect(body.video).toBeDefined();
91+
expect(body.caption).toBeDefined();
92+
expect(body.edit).toBeDefined();
93+
});
94+
});

0 commit comments

Comments
 (0)