diff --git a/src/app/api/generate/__tests__/route.test.ts b/src/app/api/generate/__tests__/route.test.ts index ec8fd9e8..7940b21e 100644 --- a/src/app/api/generate/__tests__/route.test.ts +++ b/src/app/api/generate/__tests__/route.test.ts @@ -1720,9 +1720,30 @@ describe("/api/generate route", () => { expect(data.contentType).toBe("video"); }); - it("should return 401 without API key", async () => { + it("should proceed without API key (rate-limited)", async () => { delete process.env.FAL_API_KEY; + // Schema fetch (for input mapping when no dynamicInputs) + mockFetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve({ models: [] }), + }); + + // fal.run API call succeeds without auth + mockFetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve({ + images: [{ url: "https://example.com/image.png", content_type: "image/png" }], + }), + }); + + // Image download + mockFetch.mockResolvedValueOnce({ + ok: true, + headers: new Headers({ "content-type": "image/png" }), + arrayBuffer: () => Promise.resolve(new ArrayBuffer(8)), + }); + const request = createMockPostRequest({ prompt: "A beautiful landscape", selectedModel: { @@ -1735,9 +1756,9 @@ describe("/api/generate route", () => { const response = await POST(request); const data = await response.json(); - expect(response.status).toBe(401); - expect(data.success).toBe(false); - expect(data.error).toContain("API key not configured"); + // Should proceed without key (no 401 early return) + expect(response.status).toBe(200); + expect(data.success).toBe(true); }); it("should handle rate limit (429) with API key", async () => { @@ -1775,9 +1796,22 @@ describe("/api/generate route", () => { expect(data.error).toContain("Try again in a moment"); }); - it("should return 401 for rate limit scenario without API key", async () => { + it("should handle rate limit (429) without API key", async () => { delete process.env.FAL_API_KEY; + // Schema fetch (for input mapping when no dynamicInputs) + mockFetch.mockResolvedValueOnce({ + ok: true, + json: () => Promise.resolve({ models: [] }), + }); + + // fal.run returns 429 since no auth + mockFetch.mockResolvedValueOnce({ + ok: false, + status: 429, + text: () => Promise.resolve(JSON.stringify({ detail: "Rate limit exceeded" })), + }); + const request = createMockPostRequest({ prompt: "Test prompt", selectedModel: { @@ -1790,10 +1824,10 @@ describe("/api/generate route", () => { const response = await POST(request); const data = await response.json(); - // Without API key, route returns 401 before reaching fal.ai - expect(response.status).toBe(401); + // Without API key, request proceeds but may get rate-limited by fal.ai + expect(response.status).toBe(500); expect(data.success).toBe(false); - expect(data.error).toContain("API key not configured"); + expect(data.error).toContain("Rate limit exceeded"); }); it("should handle image object response format", async () => { diff --git a/src/app/api/generate/route.ts b/src/app/api/generate/route.ts index 9e0a2bb1..2a43e8b4 100644 --- a/src/app/api/generate/route.ts +++ b/src/app/api/generate/route.ts @@ -2339,13 +2339,7 @@ export async function POST(request: NextRequest) { const falApiKey = request.headers.get("X-Fal-API-Key") || process.env.FAL_API_KEY || null; if (!falApiKey) { - return NextResponse.json( - { - success: false, - error: "fal.ai API key not configured. Add FAL_API_KEY to .env.local or configure in Settings.", - }, - { status: 401 } - ); + console.warn(`[API:${requestId}] No FAL API key configured. Proceeding without auth (rate-limited).`); } // For fal.ai, keep Data URIs as-is since localhost URLs won't work diff --git a/src/components/__tests__/AudioInputNode.test.tsx b/src/components/__tests__/AudioInputNode.test.tsx index 925c3121..4b38d537 100644 --- a/src/components/__tests__/AudioInputNode.test.tsx +++ b/src/components/__tests__/AudioInputNode.test.tsx @@ -89,7 +89,7 @@ function setMockStoreState(overrides: Record = {}) { edges: [], nodes: [], isRunning: false, - currentNodeId: null, + currentNodeIds: [], groups: {}, getNodesWithComments: vi.fn(() => []), markCommentViewed: vi.fn(), diff --git a/src/components/__tests__/EaseCurveNode.test.tsx b/src/components/__tests__/EaseCurveNode.test.tsx index 55398714..584b4e96 100644 --- a/src/components/__tests__/EaseCurveNode.test.tsx +++ b/src/components/__tests__/EaseCurveNode.test.tsx @@ -95,7 +95,7 @@ function setMockStoreState(overrides: Record = {}) { edges: [], nodes: [], isRunning: false, - currentNodeId: null, + currentNodeIds: [], groups: {}, getNodesWithComments: vi.fn(() => []), markCommentViewed: vi.fn(), diff --git a/src/components/__tests__/VideoStitchNode.test.tsx b/src/components/__tests__/VideoStitchNode.test.tsx index 2e8842c7..657928c5 100644 --- a/src/components/__tests__/VideoStitchNode.test.tsx +++ b/src/components/__tests__/VideoStitchNode.test.tsx @@ -82,7 +82,7 @@ function setMockStoreState(overrides: Record = {}) { edges: [], nodes: [], isRunning: false, - currentNodeId: null, + currentNodeIds: [], groups: {}, getNodesWithComments: vi.fn(() => []), markCommentViewed: vi.fn(),