80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import { previewSetupCsvImport } from '@/features/setup/server/csv-preview.service';
|
|
import {
|
|
assertBootstrapStepFiles,
|
|
assertBootstrapSetupAvailable,
|
|
assertBootstrapToken,
|
|
BOOTSTRAP_ACTOR_ID,
|
|
BootstrapSetupError,
|
|
setupStepStatusFromPreview,
|
|
toSerializableRecord
|
|
} from '@/features/setup/server/setup-bootstrap.service';
|
|
import { saveSetupStep, startSetupRun } from '@/features/setup/server/setup-state.service';
|
|
|
|
function isFile(value: FormDataEntryValue): value is File {
|
|
return (
|
|
typeof value === 'object' &&
|
|
'arrayBuffer' in value &&
|
|
'name' in value &&
|
|
typeof value.name === 'string' &&
|
|
value.name.trim().length > 0
|
|
);
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
await assertBootstrapSetupAvailable();
|
|
|
|
const formData = await request.formData();
|
|
assertBootstrapToken(String(formData.get('bootstrapToken') ?? request.headers.get('x-bootstrap-setup-token') ?? ''));
|
|
|
|
const stepKey = String(formData.get('stepKey') ?? '');
|
|
const uploadedFiles = Array.from(formData.values()).filter(isFile);
|
|
|
|
if (uploadedFiles.length === 0) {
|
|
return NextResponse.json({ message: 'Upload at least one setup CSV file using multipart/form-data.' }, { status: 400 });
|
|
}
|
|
|
|
const files = await Promise.all(
|
|
uploadedFiles.map(async (file) => ({
|
|
fileName: file.name,
|
|
bytes: new Uint8Array(await file.arrayBuffer())
|
|
}))
|
|
);
|
|
|
|
const step = assertBootstrapStepFiles(stepKey, files);
|
|
|
|
await startSetupRun({ actorId: BOOTSTRAP_ACTOR_ID, mode: 'production', targetOrganizationId: null });
|
|
const preview = await previewSetupCsvImport(files);
|
|
|
|
await saveSetupStep({
|
|
stepKey: step.stepKey,
|
|
status: setupStepStatusFromPreview(preview),
|
|
inputHash: preview.previewHash,
|
|
output: toSerializableRecord(preview),
|
|
errors: preview.files.flatMap((file) => file.errors),
|
|
warnings: preview.files.flatMap((file) => file.warnings)
|
|
});
|
|
|
|
return NextResponse.json(preview);
|
|
} catch (error) {
|
|
if (error instanceof BootstrapSetupError) {
|
|
return NextResponse.json({ message: error.message, details: error.details }, { status: error.status });
|
|
}
|
|
|
|
if (error instanceof TypeError && /multipart\/form-data|application\/x-www-form-urlencoded/i.test(error.message)) {
|
|
return NextResponse.json({ message: 'Upload setup CSV files using multipart/form-data.' }, { status: 400 });
|
|
}
|
|
|
|
console.error('Bootstrap preview failed');
|
|
if (error instanceof Error) {
|
|
for (const line of (error.stack ?? error.message).split('\n').slice(0, 12)) {
|
|
console.error(line);
|
|
}
|
|
} else {
|
|
console.error(error);
|
|
}
|
|
return NextResponse.json({ message: 'Unable preview bootstrap setup CSV import' }, { status: 500 });
|
|
}
|
|
}
|