mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-25 01:31:13 -05:00
feat: Implement final error coverage
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { supabase } from '@/lib/supabaseClient';
|
||||
import { invokeWithTracking } from './edgeFunctionTracking';
|
||||
import type { UploadedImage } from '@/components/upload/EntityMultiImageUploader';
|
||||
import { logger } from './logger';
|
||||
import { handleError, handleNonCriticalError } from './errorHandler';
|
||||
|
||||
export interface CloudflareUploadResponse {
|
||||
result: {
|
||||
@@ -34,20 +34,14 @@ export async function uploadPendingImages(images: UploadedImage[]): Promise<Uplo
|
||||
);
|
||||
|
||||
if (urlError || !uploadUrlData?.uploadURL) {
|
||||
logger.error('Failed to get upload URL', {
|
||||
action: 'upload_pending_images',
|
||||
fileName,
|
||||
requestId,
|
||||
error: urlError?.message || 'Unknown error',
|
||||
const error = new Error(`Failed to get upload URL for "${fileName}": ${urlError?.message || 'Unknown error'}`);
|
||||
handleError(error, {
|
||||
action: 'Get Upload URL',
|
||||
metadata: { fileName, requestId }
|
||||
});
|
||||
throw new Error(`Failed to get upload URL for "${fileName}": ${urlError?.message || 'Unknown error'}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
logger.info('Got upload URL', {
|
||||
action: 'upload_pending_images',
|
||||
fileName,
|
||||
requestId,
|
||||
});
|
||||
|
||||
// Step 2: Upload file directly to Cloudflare
|
||||
const formData = new FormData();
|
||||
@@ -60,30 +54,25 @@ export async function uploadPendingImages(images: UploadedImage[]): Promise<Uplo
|
||||
|
||||
if (!uploadResponse.ok) {
|
||||
const errorText = await uploadResponse.text();
|
||||
logger.error('Cloudflare upload failed', {
|
||||
action: 'upload_pending_images',
|
||||
fileName,
|
||||
status: uploadResponse.status,
|
||||
error: errorText,
|
||||
const error = new Error(`Upload failed for "${fileName}" (status ${uploadResponse.status}): ${errorText}`);
|
||||
handleError(error, {
|
||||
action: 'Cloudflare Upload',
|
||||
metadata: { fileName, status: uploadResponse.status }
|
||||
});
|
||||
throw new Error(`Upload failed for "${fileName}" (status ${uploadResponse.status}): ${errorText}`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const result: CloudflareUploadResponse = await uploadResponse.json();
|
||||
|
||||
if (!result.success || !result.result) {
|
||||
logger.error('Cloudflare upload unsuccessful', {
|
||||
action: 'upload_pending_images',
|
||||
fileName,
|
||||
const error = new Error(`Cloudflare upload returned unsuccessful response for "${fileName}"`);
|
||||
handleError(error, {
|
||||
action: 'Cloudflare Upload',
|
||||
metadata: { fileName }
|
||||
});
|
||||
throw new Error(`Cloudflare upload returned unsuccessful response for "${fileName}"`);
|
||||
throw error;
|
||||
}
|
||||
|
||||
logger.info('Image uploaded successfully', {
|
||||
action: 'upload_pending_images',
|
||||
fileName,
|
||||
imageId: result.result.id,
|
||||
});
|
||||
|
||||
// Clean up object URL
|
||||
URL.revokeObjectURL(image.url);
|
||||
@@ -132,10 +121,13 @@ export async function uploadPendingImages(images: UploadedImage[]): Promise<Uplo
|
||||
// If any uploads failed, clean up ONLY newly uploaded images and throw error
|
||||
if (errors.length > 0) {
|
||||
if (newlyUploadedImageIds.length > 0) {
|
||||
logger.error('Some uploads failed, cleaning up', {
|
||||
action: 'upload_pending_images',
|
||||
newlyUploadedCount: newlyUploadedImageIds.length,
|
||||
failureCount: errors.length,
|
||||
const cleanupError = new Error(`Some uploads failed, cleaning up ${newlyUploadedImageIds.length} newly uploaded images`);
|
||||
handleError(cleanupError, {
|
||||
action: 'Upload Cleanup',
|
||||
metadata: {
|
||||
newlyUploadedCount: newlyUploadedImageIds.length,
|
||||
failureCount: errors.length
|
||||
}
|
||||
});
|
||||
|
||||
// Attempt cleanup in parallel with detailed error tracking
|
||||
@@ -148,24 +140,29 @@ export async function uploadPendingImages(images: UploadedImage[]): Promise<Uplo
|
||||
)
|
||||
);
|
||||
|
||||
// Track cleanup failures for better debugging
|
||||
// Track cleanup failures silently (non-critical)
|
||||
const cleanupFailures = cleanupResults.filter(r => r.status === 'rejected');
|
||||
if (cleanupFailures.length > 0) {
|
||||
logger.error('Failed to cleanup images', {
|
||||
action: 'upload_pending_images_cleanup',
|
||||
cleanupFailures: cleanupFailures.length,
|
||||
totalCleanup: newlyUploadedImageIds.length,
|
||||
orphanedImages: newlyUploadedImageIds.filter((_, i) => cleanupResults[i].status === 'rejected'),
|
||||
});
|
||||
} else {
|
||||
logger.info('Successfully cleaned up images', {
|
||||
action: 'upload_pending_images_cleanup',
|
||||
cleanedCount: newlyUploadedImageIds.length,
|
||||
});
|
||||
handleNonCriticalError(
|
||||
new Error(`Failed to cleanup ${cleanupFailures.length} of ${newlyUploadedImageIds.length} images`),
|
||||
{
|
||||
action: 'Image Cleanup',
|
||||
metadata: {
|
||||
cleanupFailures: cleanupFailures.length,
|
||||
totalCleanup: newlyUploadedImageIds.length,
|
||||
orphanedImages: newlyUploadedImageIds.filter((_, i) => cleanupResults[i].status === 'rejected')
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Failed to upload ${errors.length} of ${images.length} images: ${errors.join('; ')}`);
|
||||
const finalError = new Error(`Failed to upload ${errors.length} of ${images.length} images: ${errors.join('; ')}`);
|
||||
handleError(finalError, {
|
||||
action: 'Image Upload',
|
||||
metadata: { failureCount: errors.length, totalCount: images.length }
|
||||
});
|
||||
throw finalError;
|
||||
}
|
||||
|
||||
// Remove the wasNewlyUploaded flag before returning
|
||||
|
||||
Reference in New Issue
Block a user