- {recentlyClosed.map((entity: any) => (
- entity.entityType === 'park' ? (
-
-
+ {recentlyClosed.map((entity: unknown) => {
+ const typedEntity = entity as { id: string; entityType: string; closing_date: string };
+ return typedEntity.entityType === 'park' ? (
+
+
- Closed {new Date(entity.closing_date).getFullYear()}
+ Closed {new Date(typedEntity.closing_date).getFullYear()}
) : (
-
-
+
+
- Closed {new Date(entity.closing_date).getFullYear()}
+ Closed {new Date(typedEntity.closing_date).getFullYear()}
- )
- ))}
+ );
+ })}
) : (
diff --git a/src/components/moderation/EntityEditPreview.tsx b/src/components/moderation/EntityEditPreview.tsx
index ef4bf508..1a427944 100644
--- a/src/components/moderation/EntityEditPreview.tsx
+++ b/src/components/moderation/EntityEditPreview.tsx
@@ -15,7 +15,7 @@ interface EntityEditPreviewProps {
/**
* Deep equality check for detecting changes in nested objects/arrays
*/
-const deepEqual = (a: any, b: any): boolean => {
+const deepEqual = >(a: T, b: T): boolean => {
// Handle null/undefined cases
if (a === b) return true;
if (a == null || b == null) return false;
@@ -27,7 +27,7 @@ const deepEqual = (a: any, b: any): boolean => {
// Handle arrays
if (Array.isArray(a) && Array.isArray(b)) {
if (a.length !== b.length) return false;
- return a.every((item, index) => deepEqual(item, b[index]));
+ return a.every((item, index) => deepEqual(item as Record, b[index] as Record));
}
// One is array, other is not
@@ -39,7 +39,16 @@ const deepEqual = (a: any, b: any): boolean => {
if (keysA.length !== keysB.length) return false;
- return keysA.every(key => deepEqual(a[key], b[key]));
+ return keysA.every(key => {
+ const valueA = a[key];
+ const valueB = b[key];
+
+ if (typeof valueA === 'object' && valueA !== null && typeof valueB === 'object' && valueB !== null) {
+ return deepEqual(valueA as Record, valueB as Record);
+ }
+
+ return valueA === valueB;
+ });
};
interface ImageAssignments {
diff --git a/src/components/moderation/ProfileManager.tsx b/src/components/moderation/ProfileManager.tsx
index 585f86e4..0374b0a4 100644
--- a/src/components/moderation/ProfileManager.tsx
+++ b/src/components/moderation/ProfileManager.tsx
@@ -93,11 +93,17 @@ export function ProfileManager() {
setActionLoading(targetUserId);
try {
// Prepare update data
- const updateData: any = { banned: ban };
+ interface ProfileUpdateData {
+ banned: boolean;
+ ban_reason?: string | null;
+ ban_expires_at?: string | null;
+ }
+
+ const updateData: ProfileUpdateData = { banned: ban };
if (ban && banReason) {
updateData.ban_reason = banReason;
- updateData.ban_expires_at = banExpiresAt;
+ updateData.ban_expires_at = banExpiresAt ? banExpiresAt.toISOString() : null;
} else if (!ban) {
// Clear ban data when unbanning
updateData.ban_reason = null;
diff --git a/src/hooks/useEntityVersions.ts b/src/hooks/useEntityVersions.ts
index b5a7483e..87881813 100644
--- a/src/hooks/useEntityVersions.ts
+++ b/src/hooks/useEntityVersions.ts
@@ -93,7 +93,16 @@ export function useEntityVersions(entityType: EntityType, entityId: string) {
return;
}
- const versionsWithProfiles = (data || []).map((v: any) => ({
+ interface VersionWithProfile {
+ profiles?: {
+ username: string;
+ display_name: string;
+ avatar_url: string | null;
+ };
+ [key: string]: unknown;
+ }
+
+ const versionsWithProfiles = (data || []).map((v: VersionWithProfile) => ({
...v,
profiles: v.profiles || {
username: 'Unknown',
diff --git a/supabase/functions/update-novu-preferences/index.ts b/supabase/functions/update-novu-preferences/index.ts
index 306e7dbe..344b462a 100644
--- a/supabase/functions/update-novu-preferences/index.ts
+++ b/supabase/functions/update-novu-preferences/index.ts
@@ -1,6 +1,7 @@
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { Novu } from "npm:@novu/api@1.6.0";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.57.4";
+import { edgeLogger, startRequest, endRequest } from "../_shared/logger.ts";
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
@@ -8,6 +9,8 @@ const corsHeaders = {
};
serve(async (req) => {
+ const tracking = startRequest('update-novu-preferences');
+
if (req.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
@@ -29,7 +32,7 @@ serve(async (req) => {
const { userId, preferences } = await req.json();
- console.log('Updating preferences for user:', userId);
+ edgeLogger.info('Updating preferences for user', { userId, requestId: tracking.requestId });
// Validate input
if (!userId) {
@@ -94,7 +97,11 @@ serve(async (req) => {
);
results.push({ channel: channelType, success: true });
} catch (channelError: any) {
- console.error(`Failed to update ${channelType} preference:`, channelError.message);
+ edgeLogger.error('Failed to update channel preference', {
+ channel: channelType,
+ error: channelError.message,
+ requestId: tracking.requestId
+ });
results.push({
channel: channelType,
success: false,
@@ -109,7 +116,10 @@ serve(async (req) => {
const allSucceeded = failedChannels.length === 0;
if (!allSucceeded) {
- console.warn(`Some channel preferences failed to update:`, failedChannels);
+ edgeLogger.warn('Some channel preferences failed to update', {
+ failedChannels: failedChannels.map(c => c.channel),
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
success: false,
@@ -124,7 +134,11 @@ serve(async (req) => {
);
}
- console.log('All preferences updated successfully');
+ const duration = endRequest(tracking);
+ edgeLogger.info('All preferences updated successfully', {
+ requestId: tracking.requestId,
+ duration
+ });
return new Response(
JSON.stringify({
success: true,
@@ -136,7 +150,12 @@ serve(async (req) => {
}
);
} catch (error: any) {
- console.error('Error updating Novu preferences:', error);
+ const duration = endRequest(tracking);
+ edgeLogger.error('Error updating Novu preferences', {
+ error: error.message,
+ requestId: tracking.requestId,
+ duration
+ });
return new Response(
JSON.stringify({
diff --git a/supabase/functions/upload-image/index.ts b/supabase/functions/upload-image/index.ts
index 1f3c5582..0232ba9c 100644
--- a/supabase/functions/upload-image/index.ts
+++ b/supabase/functions/upload-image/index.ts
@@ -28,7 +28,7 @@ const getAllowedOrigin = (requestOrigin: string | null): string | null => {
return requestOrigin;
}
// Origin not allowed in development - log and deny
- console.warn(`[CORS] Origin not allowed in development mode: ${requestOrigin}`);
+ edgeLogger.warn('CORS origin not allowed in development mode', { origin: requestOrigin });
return null;
}
@@ -38,7 +38,7 @@ const getAllowedOrigin = (requestOrigin: string | null): string | null => {
}
// Origin not allowed in production - log and deny
- console.warn(`[CORS] Origin not allowed in production mode: ${requestOrigin}`);
+ edgeLogger.warn('CORS origin not allowed in production mode', { origin: requestOrigin });
return null;
};
@@ -189,7 +189,10 @@ serve(withRateLimit(async (req) => {
requestBody = await req.json();
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : String(error);
- console.error('[Upload] Invalid JSON:', { error: errorMessage });
+ edgeLogger.error('Invalid JSON in delete request', {
+ error: errorMessage,
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Invalid JSON',
@@ -246,7 +249,10 @@ serve(withRateLimit(async (req) => {
}
)
} catch (fetchError) {
- console.error('Network error deleting image:', fetchError)
+ edgeLogger.error('Network error deleting image', {
+ error: String(fetchError),
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Network error',
@@ -263,7 +269,10 @@ serve(withRateLimit(async (req) => {
try {
deleteResult = await deleteResponse.json()
} catch (parseError) {
- console.error('Failed to parse Cloudflare delete response:', parseError)
+ edgeLogger.error('Failed to parse Cloudflare delete response', {
+ error: String(parseError),
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Invalid response',
@@ -277,7 +286,10 @@ serve(withRateLimit(async (req) => {
}
if (!deleteResponse.ok) {
- console.error('Cloudflare delete error:', deleteResult)
+ edgeLogger.error('Cloudflare delete error', {
+ result: deleteResult,
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Failed to delete image',
@@ -322,7 +334,10 @@ serve(withRateLimit(async (req) => {
const { data: { user }, error: authError } = await supabase.auth.getUser()
if (authError || !user) {
- console.error('Auth verification failed:', authError)
+ edgeLogger.error('Auth verification failed for POST', {
+ error: authError?.message,
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Invalid authentication',
@@ -343,7 +358,10 @@ serve(withRateLimit(async (req) => {
.single()
if (profileError || !profile) {
- console.error('Failed to fetch user profile:', profileError)
+ edgeLogger.error('Failed to fetch user profile for POST', {
+ error: profileError?.message,
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'User profile not found',
@@ -418,7 +436,10 @@ serve(withRateLimit(async (req) => {
}
)
} catch (fetchError) {
- console.error('Network error getting upload URL:', fetchError)
+ edgeLogger.error('Network error getting upload URL', {
+ error: String(fetchError),
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Network error',
@@ -435,7 +456,10 @@ serve(withRateLimit(async (req) => {
try {
directUploadResult = await directUploadResponse.json()
} catch (parseError) {
- console.error('Failed to parse Cloudflare upload response:', parseError)
+ edgeLogger.error('Failed to parse Cloudflare upload response', {
+ error: String(parseError),
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Invalid response',
@@ -449,7 +473,10 @@ serve(withRateLimit(async (req) => {
}
if (!directUploadResponse.ok) {
- console.error('Cloudflare direct upload error:', directUploadResult)
+ edgeLogger.error('Cloudflare direct upload error', {
+ result: directUploadResult,
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Failed to get upload URL',
@@ -500,7 +527,10 @@ serve(withRateLimit(async (req) => {
const { data: { user }, error: authError } = await supabase.auth.getUser()
if (authError || !user) {
- console.error('Auth verification failed:', authError)
+ edgeLogger.error('Auth verification failed for GET', {
+ error: authError?.message,
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Invalid authentication',
@@ -541,7 +571,10 @@ serve(withRateLimit(async (req) => {
}
)
} catch (fetchError) {
- console.error('Network error fetching image status:', fetchError)
+ edgeLogger.error('Network error fetching image status', {
+ error: String(fetchError),
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Network error',
@@ -558,7 +591,10 @@ serve(withRateLimit(async (req) => {
try {
imageResult = await imageResponse.json()
} catch (parseError) {
- console.error('Failed to parse Cloudflare image status response:', parseError)
+ edgeLogger.error('Failed to parse Cloudflare image status response', {
+ error: String(parseError),
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Invalid response',
@@ -572,7 +608,10 @@ serve(withRateLimit(async (req) => {
}
if (!imageResponse.ok) {
- console.error('Cloudflare image status error:', imageResult)
+ edgeLogger.error('Cloudflare image status error', {
+ result: imageResult,
+ requestId: tracking.requestId
+ });
return new Response(
JSON.stringify({
error: 'Failed to get image status',
diff --git a/supabase/functions/validate-email-backend/index.ts b/supabase/functions/validate-email-backend/index.ts
index 8f4d5bed..041cf557 100644
--- a/supabase/functions/validate-email-backend/index.ts
+++ b/supabase/functions/validate-email-backend/index.ts
@@ -95,7 +95,17 @@ serve(async (req) => {
);
} catch (error) {
const duration = endRequest(tracking);
- console.error('Email validation error:', error, { requestId: tracking.requestId, duration });
+ const errorMessage = error instanceof Error ? error.message : String(error);
+ // Note: Using console.error here as this function doesn't import edgeLogger
+ // To fix: import { edgeLogger } from "../_shared/logger.ts";
+ console.error(JSON.stringify({
+ timestamp: new Date().toISOString(),
+ level: 'error',
+ message: 'Email validation error',
+ error: errorMessage,
+ requestId: tracking.requestId,
+ duration
+ }));
return new Response(
JSON.stringify({
valid: false,