mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 07:51:13 -05:00
Connect to Lovable Cloud
Add centralized errorFormatter to convert various error types into readable messages, and apply it across edge functions. Replace String(error) usage with formatEdgeError, update relevant imports, fix a throw to use toError, and enhance logger to log formatted errors. Includes new errorFormatter.ts and widespread updates to 18+ edge functions plus logger integration.
This commit is contained in:
94
supabase/functions/_shared/errorFormatter.ts
Normal file
94
supabase/functions/_shared/errorFormatter.ts
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/**
|
||||||
|
* Error Formatting Utility for Edge Functions
|
||||||
|
*
|
||||||
|
* Provides robust error message extraction from various error types:
|
||||||
|
* - Standard Error objects
|
||||||
|
* - Supabase PostgresError objects (plain objects with message/details/code/hint)
|
||||||
|
* - Raw objects and primitives
|
||||||
|
*
|
||||||
|
* Eliminates "[object Object]" errors by properly extracting error details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format error objects for logging
|
||||||
|
* Handles Error objects, Supabase errors (plain objects), and primitives
|
||||||
|
*
|
||||||
|
* @param error - Any error value
|
||||||
|
* @returns Formatted, human-readable error message string
|
||||||
|
*/
|
||||||
|
export function formatEdgeError(error: unknown): string {
|
||||||
|
// Standard Error objects
|
||||||
|
if (error instanceof Error) {
|
||||||
|
return error.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object-like errors (Supabase PostgresError, etc.)
|
||||||
|
if (typeof error === 'object' && error !== null) {
|
||||||
|
const err = error as any;
|
||||||
|
|
||||||
|
// Try common error message properties
|
||||||
|
if (err.message && typeof err.message === 'string') {
|
||||||
|
// Include additional Supabase error details if present
|
||||||
|
const parts: string[] = [err.message];
|
||||||
|
|
||||||
|
if (err.details && typeof err.details === 'string') {
|
||||||
|
parts.push(`Details: ${err.details}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err.hint && typeof err.hint === 'string') {
|
||||||
|
parts.push(`Hint: ${err.hint}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err.code && typeof err.code === 'string') {
|
||||||
|
parts.push(`Code: ${err.code}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join(' | ');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some errors nest the actual error in an 'error' property
|
||||||
|
if (err.error) {
|
||||||
|
return formatEdgeError(err.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some APIs use 'msg' instead of 'message'
|
||||||
|
if (err.msg && typeof err.msg === 'string') {
|
||||||
|
return err.msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last resort: stringify the entire object
|
||||||
|
try {
|
||||||
|
const stringified = JSON.stringify(error, null, 2);
|
||||||
|
return stringified.length > 500
|
||||||
|
? stringified.substring(0, 500) + '... (truncated)'
|
||||||
|
: stringified;
|
||||||
|
} catch {
|
||||||
|
// JSON.stringify can fail on circular references
|
||||||
|
return 'Unknown error (could not stringify)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primitive values (strings, numbers, etc.)
|
||||||
|
return String(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert any error to a proper Error instance
|
||||||
|
* Use this before throwing to ensure proper stack traces
|
||||||
|
*
|
||||||
|
* @param error - Any error value
|
||||||
|
* @returns Error instance with formatted message
|
||||||
|
*/
|
||||||
|
export function toError(error: unknown): Error {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = formatEdgeError(error);
|
||||||
|
const newError = new Error(message);
|
||||||
|
|
||||||
|
// Preserve original error as property for debugging
|
||||||
|
(newError as any).originalError = error;
|
||||||
|
|
||||||
|
return newError;
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
* Prevents sensitive data exposure and provides consistent log format
|
* Prevents sensitive data exposure and provides consistent log format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { formatEdgeError } from './errorFormatter.ts';
|
||||||
|
|
||||||
type LogLevel = 'info' | 'warn' | 'error' | 'debug';
|
type LogLevel = 'info' | 'warn' | 'error' | 'debug';
|
||||||
|
|
||||||
interface LogContext {
|
interface LogContext {
|
||||||
@@ -96,16 +98,17 @@ export function startSpan(
|
|||||||
/**
|
/**
|
||||||
* End a span with final status
|
* End a span with final status
|
||||||
*/
|
*/
|
||||||
export function endSpan(span: Span, status?: 'ok' | 'error', error?: Error): Span {
|
export function endSpan(span: Span, status?: 'ok' | 'error', error?: unknown): Span {
|
||||||
span.endTime = Date.now();
|
span.endTime = Date.now();
|
||||||
span.duration = span.endTime - span.startTime;
|
span.duration = span.endTime - span.startTime;
|
||||||
span.status = status || 'ok';
|
span.status = status || 'ok';
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
const err = error instanceof Error ? error : new Error(formatEdgeError(error));
|
||||||
span.error = {
|
span.error = {
|
||||||
type: error.name,
|
type: err.name,
|
||||||
message: error.message,
|
message: err.message,
|
||||||
stack: error.stack,
|
stack: err.stack,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -348,7 +349,7 @@ Deno.serve(async (req) => {
|
|||||||
edgeLogger.warn('Error deleting avatar from Cloudflare', {
|
edgeLogger.warn('Error deleting avatar from Cloudflare', {
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
targetUserId,
|
targetUserId,
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
action: 'admin_delete_user'
|
action: 'admin_delete_user'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -417,7 +418,7 @@ Deno.serve(async (req) => {
|
|||||||
edgeLogger.warn('Error removing Novu subscriber', {
|
edgeLogger.warn('Error removing Novu subscriber', {
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
targetUserId,
|
targetUserId,
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
action: 'admin_delete_user'
|
action: 'admin_delete_user'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -521,7 +522,7 @@ Deno.serve(async (req) => {
|
|||||||
edgeLogger.warn('Error sending deletion notification email', {
|
edgeLogger.warn('Error sending deletion notification email', {
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
targetUserId,
|
targetUserId,
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
action: 'admin_delete_user'
|
action: 'admin_delete_user'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -546,7 +547,7 @@ Deno.serve(async (req) => {
|
|||||||
edgeLogger.error('Unexpected error in admin delete user', {
|
edgeLogger.error('Unexpected error in admin delete user', {
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
duration,
|
duration,
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
action: 'admin_delete_user'
|
action: 'admin_delete_user'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -137,7 +138,7 @@ serve(async (req) => {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const duration = endRequest(tracking);
|
const duration = endRequest(tracking);
|
||||||
edgeLogger.error('Error cancelling deletion', { action: 'cancel_deletion_error', error: error instanceof Error ? error.message : String(error), requestId: tracking.requestId, duration });
|
edgeLogger.error('Error cancelling deletion', { action: 'cancel_deletion_error', error: formatEdgeError(error), requestId: tracking.requestId, duration });
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({ error: error.message, requestId: tracking.requestId }),
|
JSON.stringify({ error: error.message, requestId: tracking.requestId }),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -149,7 +150,7 @@ Deno.serve(async (req) => {
|
|||||||
action: 'cancel_email_change',
|
action: 'cancel_email_change',
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
duration,
|
duration,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: formatEdgeError(error)
|
||||||
});
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||||
import { edgeLogger } from '../_shared/logger.ts';
|
import { edgeLogger } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -183,7 +184,7 @@ Deno.serve(async (req) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
edgeLogger.error('Cleanup job failed', { error: error instanceof Error ? error.message : String(error) });
|
edgeLogger.error('Cleanup job failed', { error: formatEdgeError(error) });
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
||||||
import { Novu } from "npm:@novu/api@1.6.0";
|
import { Novu } from "npm:@novu/api@1.6.0";
|
||||||
import { edgeLogger } from '../_shared/logger.ts';
|
import { edgeLogger } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -218,7 +219,7 @@ serve(async (req) => {
|
|||||||
} catch (topicError: unknown) {
|
} catch (topicError: unknown) {
|
||||||
// Non-blocking - log error but don't fail the request
|
// Non-blocking - log error but don't fail the request
|
||||||
edgeLogger.error('Failed to add subscriber to users topic', {
|
edgeLogger.error('Failed to add subscriber to users topic', {
|
||||||
error: topicError instanceof Error ? topicError.message : String(topicError),
|
error: formatEdgeError(topicError),
|
||||||
subscriberId,
|
subscriberId,
|
||||||
requestId: tracking.requestId
|
requestId: tracking.requestId
|
||||||
});
|
});
|
||||||
@@ -238,7 +239,7 @@ serve(async (req) => {
|
|||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const duration = endRequest(tracking);
|
const duration = endRequest(tracking);
|
||||||
edgeLogger.error('Error creating Novu subscriber', {
|
edgeLogger.error('Error creating Novu subscriber', {
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
duration
|
duration
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
||||||
import { edgeLogger, startRequest, endRequest } from "../_shared/logger.ts";
|
import { edgeLogger, startRequest, endRequest } from "../_shared/logger.ts";
|
||||||
|
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -45,7 +46,7 @@ function cleanupExpiredEntries() {
|
|||||||
// CRITICAL: Increment failure counter and log detailed error information
|
// CRITICAL: Increment failure counter and log detailed error information
|
||||||
cleanupFailureCount++;
|
cleanupFailureCount++;
|
||||||
|
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
const errorMessage = formatEdgeError(error);
|
||||||
|
|
||||||
edgeLogger.error('Cleanup error', {
|
edgeLogger.error('Cleanup error', {
|
||||||
attempt: cleanupFailureCount,
|
attempt: cleanupFailureCount,
|
||||||
@@ -284,7 +285,7 @@ serve(async (req) => {
|
|||||||
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
// Enhanced error logging for better visibility and debugging
|
// Enhanced error logging for better visibility and debugging
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
const errorMessage = formatEdgeError(error);
|
||||||
|
|
||||||
edgeLogger.error('Location detection error', {
|
edgeLogger.error('Location detection error', {
|
||||||
error: errorMessage,
|
error: errorMessage,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { sanitizeError } from '../_shared/errorSanitizer.ts';
|
import { sanitizeError } from '../_shared/errorSanitizer.ts';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -348,7 +349,7 @@ serve(async (req) => {
|
|||||||
action: 'export_error',
|
action: 'export_error',
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
duration,
|
duration,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: formatEdgeError(error)
|
||||||
});
|
});
|
||||||
const sanitized = sanitizeError(error, 'export-user-data');
|
const sanitized = sanitizeError(error, 'export-user-data');
|
||||||
return new Response(
|
return new Response(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -186,7 +187,7 @@ Deno.serve(async (req) => {
|
|||||||
action: 'mfa_unenroll_error',
|
action: 'mfa_unenroll_error',
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
duration,
|
duration,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: formatEdgeError(error)
|
||||||
});
|
});
|
||||||
return new Response(
|
return new Response(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
extractSpanContextFromHeaders,
|
extractSpanContextFromHeaders,
|
||||||
type Span
|
type Span
|
||||||
} from '../_shared/logger.ts';
|
} from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError, toError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const SUPABASE_URL = Deno.env.get('SUPABASE_URL') || 'https://api.thrillwiki.com';
|
const SUPABASE_URL = Deno.env.get('SUPABASE_URL') || 'https://api.thrillwiki.com';
|
||||||
const SUPABASE_ANON_KEY = Deno.env.get('SUPABASE_ANON_KEY')!;
|
const SUPABASE_ANON_KEY = Deno.env.get('SUPABASE_ANON_KEY')!;
|
||||||
@@ -277,7 +278,7 @@ const handler = async (req: Request) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (idempotencyError) {
|
if (idempotencyError) {
|
||||||
throw idempotencyError;
|
throw toError(idempotencyError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -401,7 +402,7 @@ const handler = async (req: Request) => {
|
|||||||
requestId,
|
requestId,
|
||||||
idempotencyKey,
|
idempotencyKey,
|
||||||
status: 'failed',
|
status: 'failed',
|
||||||
error: updateError instanceof Error ? updateError.message : String(updateError),
|
error: formatEdgeError(updateError),
|
||||||
action: 'process_approval'
|
action: 'process_approval'
|
||||||
});
|
});
|
||||||
// Non-blocking - continue with error response even if idempotency update fails
|
// Non-blocking - continue with error response even if idempotency update fails
|
||||||
@@ -461,7 +462,7 @@ const handler = async (req: Request) => {
|
|||||||
requestId,
|
requestId,
|
||||||
idempotencyKey,
|
idempotencyKey,
|
||||||
status: 'completed',
|
status: 'completed',
|
||||||
error: updateError instanceof Error ? updateError.message : String(updateError),
|
error: formatEdgeError(updateError),
|
||||||
action: 'process_approval'
|
action: 'process_approval'
|
||||||
});
|
});
|
||||||
// Non-blocking - transaction succeeded, so continue with success response
|
// Non-blocking - transaction succeeded, so continue with success response
|
||||||
@@ -483,13 +484,13 @@ const handler = async (req: Request) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
endSpan(rootSpan, 'error', error instanceof Error ? error : new Error(String(error)));
|
endSpan(rootSpan, 'error', error instanceof Error ? error : toError(error));
|
||||||
logSpan(rootSpan);
|
logSpan(rootSpan);
|
||||||
|
|
||||||
edgeLogger.error('Unexpected error', {
|
edgeLogger.error('Unexpected error', {
|
||||||
requestId,
|
requestId,
|
||||||
duration: rootSpan.duration,
|
duration: rootSpan.duration,
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
stack: error instanceof Error ? error.stack : undefined,
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
action: 'process_approval'
|
action: 'process_approval'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
extractSpanContextFromHeaders,
|
extractSpanContextFromHeaders,
|
||||||
type Span
|
type Span
|
||||||
} from '../_shared/logger.ts';
|
} from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError, toError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const SUPABASE_URL = Deno.env.get('SUPABASE_URL') || 'https://api.thrillwiki.com';
|
const SUPABASE_URL = Deno.env.get('SUPABASE_URL') || 'https://api.thrillwiki.com';
|
||||||
const SUPABASE_ANON_KEY = Deno.env.get('SUPABASE_ANON_KEY')!;
|
const SUPABASE_ANON_KEY = Deno.env.get('SUPABASE_ANON_KEY')!;
|
||||||
@@ -280,7 +281,7 @@ const handler = async (req: Request) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (idempotencyError) {
|
if (idempotencyError) {
|
||||||
throw idempotencyError;
|
throw toError(idempotencyError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,7 +405,7 @@ const handler = async (req: Request) => {
|
|||||||
requestId,
|
requestId,
|
||||||
idempotencyKey,
|
idempotencyKey,
|
||||||
status: 'failed',
|
status: 'failed',
|
||||||
error: updateError instanceof Error ? updateError.message : String(updateError),
|
error: formatEdgeError(updateError),
|
||||||
action: 'process_rejection'
|
action: 'process_rejection'
|
||||||
});
|
});
|
||||||
// Non-blocking - continue with error response even if idempotency update fails
|
// Non-blocking - continue with error response even if idempotency update fails
|
||||||
@@ -464,7 +465,7 @@ const handler = async (req: Request) => {
|
|||||||
requestId,
|
requestId,
|
||||||
idempotencyKey,
|
idempotencyKey,
|
||||||
status: 'completed',
|
status: 'completed',
|
||||||
error: updateError instanceof Error ? updateError.message : String(updateError),
|
error: formatEdgeError(updateError),
|
||||||
action: 'process_rejection'
|
action: 'process_rejection'
|
||||||
});
|
});
|
||||||
// Non-blocking - transaction succeeded, so continue with success response
|
// Non-blocking - transaction succeeded, so continue with success response
|
||||||
@@ -486,13 +487,13 @@ const handler = async (req: Request) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
endSpan(rootSpan, 'error', error instanceof Error ? error : new Error(String(error)));
|
endSpan(rootSpan, 'error', error instanceof Error ? error : toError(error));
|
||||||
logSpan(rootSpan);
|
logSpan(rootSpan);
|
||||||
|
|
||||||
edgeLogger.error('Unexpected error', {
|
edgeLogger.error('Unexpected error', {
|
||||||
requestId,
|
requestId,
|
||||||
duration: rootSpan.duration,
|
duration: rootSpan.duration,
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
stack: error instanceof Error ? error.stack : undefined,
|
stack: error instanceof Error ? error.stack : undefined,
|
||||||
action: 'process_rejection'
|
action: 'process_rejection'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
|||||||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
||||||
import { edgeLogger, startRequest, endRequest } from "../_shared/logger.ts";
|
import { edgeLogger, startRequest, endRequest } from "../_shared/logger.ts";
|
||||||
import { createErrorResponse } from "../_shared/errorSanitizer.ts";
|
import { createErrorResponse } from "../_shared/errorSanitizer.ts";
|
||||||
|
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -261,7 +262,7 @@ const handler = async (req: Request): Promise<Response> => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
edgeLogger.error('Unexpected error in receive-inbound-email', {
|
edgeLogger.error('Unexpected error in receive-inbound-email', {
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: formatEdgeError(error)
|
||||||
});
|
});
|
||||||
return createErrorResponse(error, 500, corsHeaders);
|
return createErrorResponse(error, 500, corsHeaders);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { edgeLogger } from '../_shared/logger.ts';
|
import { edgeLogger } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -55,7 +56,7 @@ serve(async (req: Request) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
edgeLogger.error('Maintenance exception', {
|
edgeLogger.error('Maintenance exception', {
|
||||||
requestId,
|
requestId,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: formatEdgeError(error)
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
|||||||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
||||||
import { edgeLogger, startRequest, endRequest } from "../_shared/logger.ts";
|
import { edgeLogger, startRequest, endRequest } from "../_shared/logger.ts";
|
||||||
import { createErrorResponse } from "../_shared/errorSanitizer.ts";
|
import { createErrorResponse } from "../_shared/errorSanitizer.ts";
|
||||||
|
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -237,7 +238,7 @@ const handler = async (req: Request): Promise<Response> => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
edgeLogger.error('Unexpected error in send-admin-email-reply', {
|
edgeLogger.error('Unexpected error in send-admin-email-reply', {
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: formatEdgeError(error)
|
||||||
});
|
});
|
||||||
return createErrorResponse(error, 500, corsHeaders);
|
return createErrorResponse(error, 500, corsHeaders);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
|||||||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
|
||||||
import { edgeLogger } from "../_shared/logger.ts";
|
import { edgeLogger } from "../_shared/logger.ts";
|
||||||
import { createErrorResponse } from "../_shared/errorSanitizer.ts";
|
import { createErrorResponse } from "../_shared/errorSanitizer.ts";
|
||||||
|
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -335,7 +336,7 @@ The ThrillWiki Team`,
|
|||||||
edgeLogger.error('Contact submission failed', {
|
edgeLogger.error('Contact submission failed', {
|
||||||
requestId,
|
requestId,
|
||||||
duration,
|
duration,
|
||||||
error: error instanceof Error ? error.message : String(error)
|
error: formatEdgeError(error)
|
||||||
});
|
});
|
||||||
return createErrorResponse(error, 500, corsHeaders);
|
return createErrorResponse(error, 500, corsHeaders);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.57.4';
|
||||||
import { edgeLogger } from '../_shared/logger.ts';
|
import { edgeLogger } from '../_shared/logger.ts';
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts';
|
||||||
|
|
||||||
const BASE_URL = 'https://dev.thrillwiki.com';
|
const BASE_URL = 'https://dev.thrillwiki.com';
|
||||||
|
|
||||||
@@ -347,7 +348,7 @@ Deno.serve(async (req) => {
|
|||||||
|
|
||||||
edgeLogger.error('Sitemap generation failed', {
|
edgeLogger.error('Sitemap generation failed', {
|
||||||
requestId,
|
requestId,
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
duration,
|
duration,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
|
|||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
|
||||||
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts'
|
import { edgeLogger, startRequest, endRequest } from '../_shared/logger.ts'
|
||||||
import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts'
|
import { rateLimiters, withRateLimit } from '../_shared/rateLimiter.ts'
|
||||||
|
import { formatEdgeError } from '../_shared/errorFormatter.ts'
|
||||||
|
|
||||||
// Environment-aware CORS configuration
|
// Environment-aware CORS configuration
|
||||||
const getAllowedOrigin = (requestOrigin: string | null): string | null => {
|
const getAllowedOrigin = (requestOrigin: string | null): string | null => {
|
||||||
@@ -94,7 +95,7 @@ async function reportBanEvasionToAlerts(
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Non-blocking - log but don't fail the response
|
// Non-blocking - log but don't fail the response
|
||||||
edgeLogger.warn('Failed to report ban evasion', {
|
edgeLogger.warn('Failed to report ban evasion', {
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: formatEdgeError(error),
|
||||||
requestId
|
requestId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -227,8 +228,8 @@ serve(withRateLimit(async (req) => {
|
|||||||
try {
|
try {
|
||||||
requestBody = await req.json();
|
requestBody = await req.json();
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
const errorMessage = formatEdgeError(error);
|
||||||
edgeLogger.error('Invalid JSON in delete request', {
|
edgeLogger.error('Invalid JSON in delete request', {
|
||||||
error: errorMessage,
|
error: errorMessage,
|
||||||
requestId: tracking.requestId
|
requestId: tracking.requestId
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
||||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.39.3';
|
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2.39.3';
|
||||||
import { edgeLogger } from "../_shared/logger.ts";
|
import { edgeLogger } from "../_shared/logger.ts";
|
||||||
|
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -96,7 +97,7 @@ serve(async (req) => {
|
|||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const duration = endRequest(tracking);
|
const duration = endRequest(tracking);
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
const errorMessage = formatEdgeError(error);
|
||||||
edgeLogger.error('Email validation error', {
|
edgeLogger.error('Email validation error', {
|
||||||
error: errorMessage,
|
error: errorMessage,
|
||||||
requestId: tracking.requestId,
|
requestId: tracking.requestId,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
import { serve } from "https://deno.land/std@0.190.0/http/server.ts";
|
||||||
import { startRequest, endRequest, edgeLogger } from "../_shared/logger.ts";
|
import { startRequest, endRequest, edgeLogger } from "../_shared/logger.ts";
|
||||||
|
import { formatEdgeError } from "../_shared/errorFormatter.ts";
|
||||||
|
|
||||||
const corsHeaders = {
|
const corsHeaders = {
|
||||||
'Access-Control-Allow-Origin': '*',
|
'Access-Control-Allow-Origin': '*',
|
||||||
@@ -180,7 +181,7 @@ const handler = async (req: Request): Promise<Response> => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
const errorMessage = formatEdgeError(error);
|
||||||
edgeLogger.error('Error in validate-email function', {
|
edgeLogger.error('Error in validate-email function', {
|
||||||
error: errorMessage,
|
error: errorMessage,
|
||||||
requestId: tracking.requestId
|
requestId: tracking.requestId
|
||||||
|
|||||||
Reference in New Issue
Block a user