mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 09:51:13 -05:00
Implement Phase 3: Enhanced Error Handling
This commit implements Phase 3 of the Sacred Pipeline, focusing on enhanced error handling. It includes: - **Transaction Status Polling Endpoint**: A new edge function `check-transaction-status` allows clients to poll the status of moderation transactions using idempotency keys. - **Expanded Error Sanitizer Patterns**: The `src/lib/errorSanitizer.ts` file has been updated with more comprehensive patterns to remove sensitive information from error messages, making them safer for display and logging. User-friendly replacements for common errors are also included. - **Rate Limiting for Submission Creation**: Client-side rate limiting has been implemented in `src/lib/submissionRateLimiter.ts` and applied to key submission functions within `src/lib/entitySubmissionHelpers.ts` (e.g., `submitParkCreation`, `submitRideCreation`, `submitParkUpdate`, `submitRideUpdate`) to prevent abuse and accidental duplicate submissions.
This commit is contained in:
@@ -17,6 +17,8 @@ import {
|
||||
validateRideModelCreateFields,
|
||||
assertValid
|
||||
} from './submissionValidation';
|
||||
import { checkSubmissionRateLimit, recordSubmissionAttempt } from './submissionRateLimiter';
|
||||
import { sanitizeErrorMessage } from './errorSanitizer';
|
||||
|
||||
// ============================================
|
||||
// COMPOSITE SUBMISSION TYPES
|
||||
@@ -198,6 +200,37 @@ export interface RideModelFormData {
|
||||
_technical_specifications?: TechnicalSpecification[];
|
||||
}
|
||||
|
||||
/**
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
* RATE LIMITING HELPER
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
*
|
||||
* Checks rate limits before allowing submission creation
|
||||
* Part of Sacred Pipeline Phase 3: Enhanced Error Handling
|
||||
*/
|
||||
function checkRateLimitOrThrow(userId: string, action: string): void {
|
||||
const rateLimit = checkSubmissionRateLimit(userId);
|
||||
|
||||
if (!rateLimit.allowed) {
|
||||
const sanitizedMessage = sanitizeErrorMessage(rateLimit.reason || 'Rate limit exceeded');
|
||||
|
||||
logger.warn('[RateLimit] Submission blocked', {
|
||||
userId,
|
||||
action,
|
||||
reason: rateLimit.reason,
|
||||
retryAfter: rateLimit.retryAfter,
|
||||
});
|
||||
|
||||
throw new Error(sanitizedMessage);
|
||||
}
|
||||
|
||||
logger.info('[RateLimit] Submission allowed', {
|
||||
userId,
|
||||
action,
|
||||
remaining: rateLimit.remaining,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* ═══════════════════════════════════════════════════════════════════
|
||||
* COMPOSITE SUBMISSION HANDLER
|
||||
@@ -220,6 +253,9 @@ async function submitCompositeCreation(
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
try {
|
||||
// Phase 3: Rate limiting check
|
||||
checkRateLimitOrThrow(userId, 'composite_creation');
|
||||
|
||||
breadcrumb.userAction('Start composite submission', 'submitCompositeCreation', {
|
||||
primaryType: primaryEntity.type,
|
||||
dependencyCount: dependencies.length,
|
||||
@@ -624,6 +660,9 @@ export async function submitParkCreation(
|
||||
data: ParkFormData & { _compositeSubmission?: any },
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Phase 3: Rate limiting check
|
||||
checkRateLimitOrThrow(userId, 'park_creation');
|
||||
|
||||
console.info('[submitParkCreation] Received data:', {
|
||||
hasLocation: !!data.location,
|
||||
hasLocationId: !!data.location_id,
|
||||
@@ -884,6 +923,9 @@ export async function submitParkUpdate(
|
||||
data: ParkFormData,
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Phase 3: Rate limiting check
|
||||
checkRateLimitOrThrow(userId, 'park_update');
|
||||
|
||||
const { withRetry, isRetryableError } = await import('./retryHelpers');
|
||||
|
||||
// Check if user is banned - with retry for transient failures
|
||||
@@ -1120,6 +1162,9 @@ export async function submitRideCreation(
|
||||
},
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Phase 3: Rate limiting check
|
||||
checkRateLimitOrThrow(userId, 'ride_creation');
|
||||
|
||||
// Validate required fields client-side
|
||||
assertValid(validateRideCreateFields(data));
|
||||
|
||||
@@ -1504,6 +1549,9 @@ export async function submitRideUpdate(
|
||||
data: RideFormData,
|
||||
userId: string
|
||||
): Promise<{ submitted: boolean; submissionId: string }> {
|
||||
// Phase 3: Rate limiting check
|
||||
checkRateLimitOrThrow(userId, 'ride_update');
|
||||
|
||||
const { withRetry, isRetryableError } = await import('./retryHelpers');
|
||||
|
||||
// Check if user is banned - with retry for transient failures
|
||||
|
||||
Reference in New Issue
Block a user