Browse Source

fix: use presigned URLs for fetching large community workflows

Update the community workflow API to fetch presigned URLs from
node-banana-pro, then download workflows directly from R2. This
avoids timeouts when fetching large workflow files (275MB+).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 6 months ago
parent
commit
69984faa58
  1. 67
      src/app/api/community-workflows/[id]/route.ts

67
src/app/api/community-workflows/[id]/route.ts

@ -13,7 +13,8 @@ interface RouteParams {
* GET: Load a specific community workflow by ID from the remote API
*
* This proxies to the node-banana-pro hosted service which stores
* community workflows in R2 storage.
* community workflows in R2 storage. The API returns a presigned URL
* which we use to fetch the actual workflow data directly from R2.
*/
export async function GET(request: Request, { params }: RouteParams) {
const controller = new AbortController();
@ -22,22 +23,22 @@ export async function GET(request: Request, { params }: RouteParams) {
try {
const { id } = await params;
const response = await fetch(
// Step 1: Get the presigned URL from the API
const urlResponse = await fetch(
`${COMMUNITY_WORKFLOWS_API_URL}/${encodeURIComponent(id)}`,
{
headers: {
Accept: "application/json",
},
signal: controller.signal,
// Cache for 10 minutes (individual workflows change less frequently)
next: { revalidate: 600 },
// Short cache since presigned URLs expire
next: { revalidate: 60 },
}
);
clearTimeout(timeoutId);
if (!response.ok) {
if (response.status === 404) {
if (!urlResponse.ok) {
clearTimeout(timeoutId);
if (urlResponse.status === 404) {
return NextResponse.json(
{
success: false,
@ -48,22 +49,60 @@ export async function GET(request: Request, { params }: RouteParams) {
}
console.error(
"Error fetching community workflow:",
response.status,
response.statusText
"Error fetching community workflow URL:",
urlResponse.status,
urlResponse.statusText
);
return NextResponse.json(
{
success: false,
error: "Failed to load workflow",
},
{ status: response.status }
{ status: urlResponse.status }
);
}
const urlData = await urlResponse.json();
if (!urlData.success || !urlData.downloadUrl) {
clearTimeout(timeoutId);
return NextResponse.json(
{
success: false,
error: urlData.error || "Failed to get download URL",
},
{ status: 500 }
);
}
// Step 2: Fetch the actual workflow from the presigned R2 URL
const workflowResponse = await fetch(urlData.downloadUrl, {
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!workflowResponse.ok) {
console.error(
"Error fetching workflow from R2:",
workflowResponse.status,
workflowResponse.statusText
);
return NextResponse.json(
{
success: false,
error: "Failed to download workflow",
},
{ status: 500 }
);
}
const data = await response.json();
const workflow = await workflowResponse.json();
return NextResponse.json(data);
return NextResponse.json({
success: true,
workflow,
});
} catch (error) {
clearTimeout(timeoutId);

Loading…
Cancel
Save