made add company details api and moved it in the host folder

This commit is contained in:
2025-11-13 15:53:35 +05:30
parent 8e19bb566d
commit 72f9e26ca6
13 changed files with 513 additions and 268 deletions

View File

@@ -0,0 +1,126 @@
import ApiError from './ApiError';
interface ParsedFormData {
fields: Record<string, string>;
files: Array<{
fieldName: string;
fileName: string;
contentType: string;
data: Buffer;
}>;
}
/**
* Parse multipart/form-data from Lambda event
* Supports both base64 encoded and binary body
*/
export function parseMultipartFormData(
eventBody: string | null,
contentType: string | undefined,
isBase64Encoded: boolean = false
): ParsedFormData {
if (!eventBody) {
throw new ApiError(400, 'Request body is required');
}
if (!contentType || !contentType.includes('multipart/form-data')) {
throw new ApiError(400, 'Content-Type must be multipart/form-data');
}
// Extract boundary from Content-Type header
const boundaryMatch = contentType.match(/boundary=([^;]+)/);
if (!boundaryMatch) {
throw new ApiError(400, 'Invalid multipart boundary');
}
const boundary = boundaryMatch[1].trim();
// Decode base64 body if needed (API Gateway sends base64 encoded for binary media types)
let bodyBuffer: Buffer;
try {
if (isBase64Encoded) {
bodyBuffer = Buffer.from(eventBody, 'base64');
} else {
// Try to detect if it's base64
if (eventBody.match(/^[A-Za-z0-9+/=]+$/)) {
bodyBuffer = Buffer.from(eventBody, 'base64');
} else {
bodyBuffer = Buffer.from(eventBody, 'binary');
}
}
} catch (error) {
throw new ApiError(400, 'Invalid request body encoding');
}
// Split by boundary
const parts = bodyBuffer.toString('binary').split(`--${boundary}`);
const fields: Record<string, string> = {};
const files: ParsedFormData['files'] = [];
for (const part of parts) {
if (!part || part.trim() === '' || part.trim() === '--') {
continue;
}
// Split headers and body
const [headers, ...bodyParts] = part.split('\r\n\r\n');
if (!headers || bodyParts.length === 0) {
continue;
}
const body = bodyParts.join('\r\n\r\n').trim();
if (!body) {
continue;
}
// Parse Content-Disposition header
const contentDispositionMatch = headers.match(/Content-Disposition:\s*form-data;\s*name="([^"]+)"/);
if (!contentDispositionMatch) {
continue;
}
const fieldName = contentDispositionMatch[1];
// Check if it's a file
const filenameMatch = headers.match(/filename="([^"]+)"/);
const contentTypeMatch = headers.match(/Content-Type:\s*([^\r\n]+)/);
if (filenameMatch) {
// It's a file
const fileName = filenameMatch[1];
const fileContentType = contentTypeMatch ? contentTypeMatch[1].trim() : 'application/octet-stream';
// Convert body to buffer (remove trailing boundary markers)
const fileData = Buffer.from(body.replace(/\r\n--$/, ''), 'binary');
files.push({
fieldName,
fileName,
contentType: fileContentType,
data: fileData,
});
} else {
// It's a regular field
fields[fieldName] = body.replace(/\r\n--$/, '').trim();
}
}
return { fields, files };
}
/**
* Parse JSON field from form data
*/
export function parseJsonField(fields: Record<string, string>, fieldName: string): any {
const value = fields[fieldName];
if (!value) {
return null;
}
try {
return JSON.parse(value);
} catch (error) {
throw new ApiError(400, `Invalid JSON in field: ${fieldName}`);
}
}