Files
thrilltrack-explorer/supabase/functions/detect-location/index.ts
pac7 32a83013e5 Update email cancellation and location detection functions
Refactor Supabase function to use explicit JWT verification via auth.getUser, and enhance the location detection function with configurable geolocation API endpoints.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 364fb426-1d27-49b2-a244-a34e41c335e4
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
2025-10-08 12:32:19 +00:00

100 lines
3.0 KiB
TypeScript

import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};
interface IPLocationResponse {
country: string;
countryCode: string;
measurementSystem: 'metric' | 'imperial';
}
serve(async (req) => {
// Handle CORS preflight requests
if (req.method === 'OPTIONS') {
return new Response(null, { headers: corsHeaders });
}
try {
// Get the client's IP address
const forwarded = req.headers.get('x-forwarded-for');
const realIP = req.headers.get('x-real-ip');
const clientIP = forwarded?.split(',')[0] || realIP || '8.8.8.8'; // fallback to Google DNS for testing
console.log('Detecting location for IP:', clientIP);
// Use configurable geolocation service with proper error handling
// Defaults to ip-api.com if not configured
const geoApiUrl = Deno.env.get('GEOLOCATION_API_URL') || 'http://ip-api.com/json';
const geoApiFields = Deno.env.get('GEOLOCATION_API_FIELDS') || 'status,country,countryCode';
let geoResponse;
try {
geoResponse = await fetch(`${geoApiUrl}/${clientIP}?fields=${geoApiFields}`);
} catch (fetchError) {
console.error('Network error fetching location data:', fetchError);
throw new Error('Network error: Unable to reach geolocation service');
}
if (!geoResponse.ok) {
throw new Error(`Geolocation service returned ${geoResponse.status}: ${geoResponse.statusText}`);
}
let geoData;
try {
geoData = await geoResponse.json();
} catch (parseError) {
console.error('Failed to parse geolocation response:', parseError);
throw new Error('Invalid response format from geolocation service');
}
if (geoData.status !== 'success') {
throw new Error(`Geolocation failed: ${geoData.message || 'Invalid location data'}`);
}
// Countries that primarily use imperial system
const imperialCountries = ['US', 'LR', 'MM']; // USA, Liberia, Myanmar
const measurementSystem = imperialCountries.includes(geoData.countryCode) ? 'imperial' : 'metric';
const result: IPLocationResponse = {
country: geoData.country,
countryCode: geoData.countryCode,
measurementSystem
};
console.log('Location detected:', result);
return new Response(
JSON.stringify(result),
{
headers: {
...corsHeaders,
'Content-Type': 'application/json'
}
}
);
} catch (error) {
console.error('Error detecting location:', error);
// Return default (metric) on error
const defaultResult: IPLocationResponse = {
country: 'Unknown',
countryCode: 'XX',
measurementSystem: 'metric'
};
return new Response(
JSON.stringify(defaultResult),
{
headers: {
...corsHeaders,
'Content-Type': 'application/json'
},
status: 200 // Return 200 even on error to provide fallback
}
);
}
});