./kaisetsu-app/src/app/api/upload-url/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { Storage } from '@google-cloud/storage';
import { STORAGE_BACKEND, SIGNING_SERVICE_ACCOUNT_EMAIL, GCP_REGION, requiredGcp } from '@/lib/config';
export async function POST(request: NextRequest) {
if (STORAGE_BACKEND !== 'gcs') {
return NextResponse.json(
{ error: 'Signed URLs are only available with the GCS backend. Use /api/upload instead.' },
{ status: 501 }
);
}
if (!SIGNING_SERVICE_ACCOUNT_EMAIL) {
return NextResponse.json(
{ error: 'SIGNING_SERVICE_ACCOUNT_EMAIL is not configured.' },
{ status: 500 }
);
}
try {
const { fileName, contentType } = await request.json();
if (!fileName || !contentType) {
return NextResponse.json({ error: 'fileName and contentType are required' }, { status: 400 });
}
const { projectId, bucket: bucketName } = requiredGcp();
const gcs = new Storage({ projectId });
const bucket = gcs.bucket(bucketName);
const [exists] = await bucket.exists();
if (!exists) {
await gcs.createBucket(bucketName, {
location: GCP_REGION.toUpperCase(),
storageClass: 'STANDARD',
});
}
const gcsFileName = `videos/${Date.now()}-${fileName}`;
const blob = bucket.file(gcsFileName);
const [signedUrl] = await blob.getSignedUrl({
version: 'v4',
action: 'write',
expires: Date.now() + 30 * 60 * 1000,
contentType,
signingEndpoint: `https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SIGNING_SERVICE_ACCOUNT_EMAIL}`,
});
return NextResponse.json({
signedUrl,
gcsUri: `gs://${bucketName}/${gcsFileName}`,
});
} catch (error) {
console.error('Upload URL generation error:', error);
return NextResponse.json(
{ error: error instanceof Error ? error.message : 'Failed to generate upload URL' },
{ status: 500 }
);
}
}