diff --git a/src/lib/entitySubmissionHelpers.ts b/src/lib/entitySubmissionHelpers.ts index ee1f72d1..9796d0c3 100644 --- a/src/lib/entitySubmissionHelpers.ts +++ b/src/lib/entitySubmissionHelpers.ts @@ -773,6 +773,8 @@ export async function submitParkCreation( } // Create submission with retry logic + const retryId = crypto.randomUUID(); + const result = await withRetry( async () => { // Create the main submission record @@ -882,12 +884,13 @@ export async function submitParkCreation( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { - logger.warn('Retrying park submission', { attempt, delay }); + logger.warn('Retrying park submission', { attempt, delay, error: error instanceof Error ? error.message : String(error) }); // Emit event for UI indicator window.dispatchEvent(new CustomEvent('submission-retry', { - detail: { attempt, maxAttempts: 3, delay, type: 'park' } + detail: { id: retryId, attempt, maxAttempts: 3, delay, type: 'park' } })); }, shouldRetry: (error) => { @@ -896,18 +899,35 @@ export async function submitParkCreation( const message = error.message.toLowerCase(); if (message.includes('required')) return false; if (message.includes('banned')) return false; + if (message.includes('suspended')) return false; if (message.includes('slug')) return false; + if (message.includes('already exists')) return false; + if (message.includes('duplicate')) return false; if (message.includes('permission')) return false; + if (message.includes('forbidden')) return false; + if (message.includes('unauthorized')) return false; } return isRetryableError(error); } } - ).catch((error) => { - handleError(error, { + ).then((data) => { + // Emit success event + window.dispatchEvent(new CustomEvent('submission-retry-success', { + detail: { id: retryId } + })); + return data; + }).catch((error) => { + const errorId = handleError(error, { action: 'Park submission', metadata: { retriesExhausted: true }, }); + + // Emit failure event + window.dispatchEvent(new CustomEvent('submission-retry-failed', { + detail: { id: retryId, errorId } + })); + throw error; }); @@ -1103,6 +1123,7 @@ export async function submitParkUpdate( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { logger.warn('Retrying park update submission', { attempt, @@ -1506,8 +1527,13 @@ export async function submitRideCreation( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { - logger.warn('Retrying ride submission', { attempt, delay }); + logger.warn('Retrying ride submission', { + attempt, + delay, + error: error instanceof Error ? error.message : String(error) + }); // Emit event for UI indicator window.dispatchEvent(new CustomEvent('submission-retry', { @@ -1520,8 +1546,13 @@ export async function submitRideCreation( const message = error.message.toLowerCase(); if (message.includes('required')) return false; if (message.includes('banned')) return false; + if (message.includes('suspended')) return false; if (message.includes('slug')) return false; + if (message.includes('already exists')) return false; + if (message.includes('duplicate')) return false; if (message.includes('permission')) return false; + if (message.includes('forbidden')) return false; + if (message.includes('unauthorized')) return false; } return isRetryableError(error); @@ -1714,6 +1745,7 @@ export async function submitRideUpdate( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { logger.warn('Retrying ride update submission', { attempt, @@ -1733,8 +1765,13 @@ export async function submitRideUpdate( const message = error.message.toLowerCase(); if (message.includes('required')) return false; if (message.includes('banned')) return false; + if (message.includes('suspended')) return false; if (message.includes('slug')) return false; + if (message.includes('already exists')) return false; + if (message.includes('duplicate')) return false; if (message.includes('permission')) return false; + if (message.includes('forbidden')) return false; + if (message.includes('unauthorized')) return false; if (message.includes('not found')) return false; if (message.includes('not allowed')) return false; } @@ -1838,6 +1875,8 @@ export async function submitRideModelCreation( // Submit with retry logic breadcrumb.apiCall('content_submissions', 'INSERT'); + const retryId = crypto.randomUUID(); + const result = await withRetry( async () => { // Create the main submission record @@ -1925,10 +1964,15 @@ export async function submitRideModelCreation( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { - logger.warn('Retrying ride model submission', { attempt, delay }); + logger.warn('Retrying ride model submission', { + attempt, + delay, + error: error instanceof Error ? error.message : String(error) + }); window.dispatchEvent(new CustomEvent('submission-retry', { - detail: { attempt, maxAttempts: 3, delay, type: 'ride_model' } + detail: { id: retryId, attempt, maxAttempts: 3, delay, type: 'ride_model' } })); }, shouldRetry: (error) => { @@ -1936,12 +1980,36 @@ export async function submitRideModelCreation( const message = error.message.toLowerCase(); if (message.includes('required')) return false; if (message.includes('banned')) return false; + if (message.includes('suspended')) return false; if (message.includes('slug')) return false; + if (message.includes('already exists')) return false; + if (message.includes('duplicate')) return false; + if (message.includes('permission')) return false; + if (message.includes('forbidden')) return false; + if (message.includes('unauthorized')) return false; } return isRetryableError(error); } } - ); + ).then((data) => { + // Emit success event + window.dispatchEvent(new CustomEvent('submission-retry-success', { + detail: { id: retryId } + })); + return data; + }).catch((error) => { + const errorId = handleError(error, { + action: 'Ride model submission', + metadata: { retriesExhausted: true }, + }); + + // Emit failure event + window.dispatchEvent(new CustomEvent('submission-retry-failed', { + detail: { id: retryId, errorId } + })); + + throw error; + }); return result; } @@ -2006,6 +2074,8 @@ export async function submitRideModelUpdate( // Submit with retry logic breadcrumb.apiCall('content_submissions', 'INSERT'); + const retryId = crypto.randomUUID(); + const result = await withRetry( async () => { // Create the main submission record @@ -2091,10 +2161,15 @@ export async function submitRideModelUpdate( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { - logger.warn('Retrying ride model update', { attempt, delay }); + logger.warn('Retrying ride model update', { + attempt, + delay, + error: error instanceof Error ? error.message : String(error) + }); window.dispatchEvent(new CustomEvent('submission-retry', { - detail: { attempt, maxAttempts: 3, delay, type: 'ride_model_update' } + detail: { id: retryId, attempt, maxAttempts: 3, delay, type: 'ride_model_update' } })); }, shouldRetry: (error) => { @@ -2102,12 +2177,34 @@ export async function submitRideModelUpdate( const message = error.message.toLowerCase(); if (message.includes('required')) return false; if (message.includes('banned')) return false; + if (message.includes('suspended')) return false; if (message.includes('slug')) return false; + if (message.includes('already exists')) return false; + if (message.includes('duplicate')) return false; + if (message.includes('permission')) return false; + if (message.includes('forbidden')) return false; + if (message.includes('unauthorized')) return false; } return isRetryableError(error); } } - ); + ).then((data) => { + window.dispatchEvent(new CustomEvent('submission-retry-success', { + detail: { id: retryId } + })); + return data; + }).catch((error) => { + const errorId = handleError(error, { + action: 'Ride model update submission', + metadata: { retriesExhausted: true }, + }); + + window.dispatchEvent(new CustomEvent('submission-retry-failed', { + detail: { id: retryId, errorId } + })); + + throw error; + }); return result; } @@ -2170,6 +2267,8 @@ export async function submitManufacturerCreation( // Submit with retry logic breadcrumb.apiCall('content_submissions', 'INSERT'); + const retryId = crypto.randomUUID(); + const result = await withRetry( async () => { const { data: submissionData, error: submissionError } = await supabase @@ -2209,10 +2308,15 @@ export async function submitManufacturerCreation( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { - logger.warn('Retrying manufacturer submission', { attempt, delay }); + logger.warn('Retrying manufacturer submission', { + attempt, + delay, + error: error instanceof Error ? error.message : String(error) + }); window.dispatchEvent(new CustomEvent('submission-retry', { - detail: { attempt, maxAttempts: 3, delay, type: 'manufacturer' } + detail: { id: retryId, attempt, maxAttempts: 3, delay, type: 'manufacturer' } })); }, shouldRetry: (error) => { @@ -2220,12 +2324,34 @@ export async function submitManufacturerCreation( const message = error.message.toLowerCase(); if (message.includes('required')) return false; if (message.includes('banned')) return false; + if (message.includes('suspended')) return false; if (message.includes('slug')) return false; + if (message.includes('already exists')) return false; + if (message.includes('duplicate')) return false; + if (message.includes('permission')) return false; + if (message.includes('forbidden')) return false; + if (message.includes('unauthorized')) return false; } return isRetryableError(error); } } - ); + ).then((data) => { + window.dispatchEvent(new CustomEvent('submission-retry-success', { + detail: { id: retryId } + })); + return data; + }).catch((error) => { + const errorId = handleError(error, { + action: 'Manufacturer submission', + metadata: { retriesExhausted: true }, + }); + + window.dispatchEvent(new CustomEvent('submission-retry-failed', { + detail: { id: retryId, errorId } + })); + + throw error; + }); return result; } @@ -2618,6 +2744,8 @@ export async function submitOperatorCreation( // Submit with retry logic breadcrumb.apiCall('content_submissions', 'INSERT'); + const retryId = crypto.randomUUID(); + const result = await withRetry( async () => { const { data: submissionData, error: submissionError } = await supabase @@ -2657,10 +2785,15 @@ export async function submitOperatorCreation( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { - logger.warn('Retrying operator submission', { attempt, delay }); + logger.warn('Retrying operator submission', { + attempt, + delay, + error: error instanceof Error ? error.message : String(error) + }); window.dispatchEvent(new CustomEvent('submission-retry', { - detail: { attempt, maxAttempts: 3, delay, type: 'operator' } + detail: { id: retryId, attempt, maxAttempts: 3, delay, type: 'operator' } })); }, shouldRetry: (error) => { @@ -2668,12 +2801,34 @@ export async function submitOperatorCreation( const message = error.message.toLowerCase(); if (message.includes('required')) return false; if (message.includes('banned')) return false; + if (message.includes('suspended')) return false; if (message.includes('slug')) return false; + if (message.includes('already exists')) return false; + if (message.includes('duplicate')) return false; + if (message.includes('permission')) return false; + if (message.includes('forbidden')) return false; + if (message.includes('unauthorized')) return false; } return isRetryableError(error); } } - ); + ).then((data) => { + window.dispatchEvent(new CustomEvent('submission-retry-success', { + detail: { id: retryId } + })); + return data; + }).catch((error) => { + const errorId = handleError(error, { + action: 'Operator submission', + metadata: { retriesExhausted: true }, + }); + + window.dispatchEvent(new CustomEvent('submission-retry-failed', { + detail: { id: retryId, errorId } + })); + + throw error; + }); return result; } @@ -2731,6 +2886,8 @@ export async function submitOperatorUpdate( // Submit with retry logic breadcrumb.apiCall('content_submissions', 'INSERT'); + const retryId = crypto.randomUUID(); + const result = await withRetry( async () => { const { data: submissionData, error: submissionError } = await supabase @@ -2842,6 +2999,8 @@ export async function submitPropertyOwnerCreation( // Submit with retry logic breadcrumb.apiCall('content_submissions', 'INSERT'); + const retryId = crypto.randomUUID(); + const result = await withRetry( async () => { const { data: submissionData, error: submissionError } = await supabase @@ -2881,10 +3040,15 @@ export async function submitPropertyOwnerCreation( }, { maxAttempts: 3, + baseDelay: 1000, onRetry: (attempt, error, delay) => { - logger.warn('Retrying property owner submission', { attempt, delay }); + logger.warn('Retrying property owner submission', { + attempt, + delay, + error: error instanceof Error ? error.message : String(error) + }); window.dispatchEvent(new CustomEvent('submission-retry', { - detail: { attempt, maxAttempts: 3, delay, type: 'property_owner' } + detail: { id: retryId, attempt, maxAttempts: 3, delay, type: 'property_owner' } })); }, shouldRetry: (error) => { @@ -2892,12 +3056,34 @@ export async function submitPropertyOwnerCreation( const message = error.message.toLowerCase(); if (message.includes('required')) return false; if (message.includes('banned')) return false; + if (message.includes('suspended')) return false; if (message.includes('slug')) return false; + if (message.includes('already exists')) return false; + if (message.includes('duplicate')) return false; + if (message.includes('permission')) return false; + if (message.includes('forbidden')) return false; + if (message.includes('unauthorized')) return false; } return isRetryableError(error); } } - ); + ).then((data) => { + window.dispatchEvent(new CustomEvent('submission-retry-success', { + detail: { id: retryId } + })); + return data; + }).catch((error) => { + const errorId = handleError(error, { + action: 'Property owner submission', + metadata: { retriesExhausted: true }, + }); + + window.dispatchEvent(new CustomEvent('submission-retry-failed', { + detail: { id: retryId, errorId } + })); + + throw error; + }); return result; }