// Product Lookup Edge Function // Fetches product data from Open Food Facts API by barcode import { serve } from 'https://deno.land/std@0.168.0/http/server.ts' import { createClient } from 'https://esm.sh/@supabase/supabase-js@2' const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', } interface ProductData { barcode: string name: string brand?: string quantity?: string image_url?: string category?: string cached?: boolean } serve(async (req) => { // Handle CORS preflight if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }) } try { const { barcode } = await req.json() if (!barcode) { throw new Error('Barcode is required') } // Initialize Supabase client const supabaseUrl = Deno.env.get('SUPABASE_URL')! const supabaseKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')! const supabase = createClient(supabaseUrl, supabaseKey) // Check cache first (products table can store known products) const { data: cachedProduct } = await supabase .from('products') .select('*') .eq('barcode', barcode) .single() if (cachedProduct) { console.log(`Cache HIT for barcode: ${barcode}`) return new Response( JSON.stringify({ barcode: cachedProduct.barcode, name: cachedProduct.name, brand: cachedProduct.brand, quantity: cachedProduct.quantity, image_url: cachedProduct.image_url, category: cachedProduct.category, cached: true, } as ProductData), { headers: { ...corsHeaders, 'Content-Type': 'application/json' } } ) } console.log(`Cache MISS for barcode: ${barcode}, fetching from Open Food Facts...`) // Fetch from Open Food Facts const offResponse = await fetch( `https://world.openfoodfacts.org/api/v2/product/${barcode}.json`, { headers: { 'User-Agent': 'Pantry/1.0 (https://github.com/pantry-app/pantry)', }, } ) if (!offResponse.ok) { throw new Error(`Open Food Facts API error: ${offResponse.status}`) } const offData = await offResponse.json() if (offData.status !== 1 || !offData.product) { // Product not found in Open Food Facts return new Response( JSON.stringify({ barcode, name: `Unknown Product (${barcode})`, cached: false, } as ProductData), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 404 } ) } const product = offData.product // Extract relevant data const productData: ProductData = { barcode, name: product.product_name || product.generic_name || `Product ${barcode}`, brand: product.brands || undefined, quantity: product.quantity || undefined, image_url: product.image_url || product.image_front_url || undefined, category: product.categories || undefined, cached: false, } // Cache the product in our database (upsert) await supabase.from('products').upsert({ barcode: productData.barcode, name: productData.name, brand: productData.brand, quantity: productData.quantity, image_url: productData.image_url, category: productData.category, }, { onConflict: 'barcode' }) console.log(`Successfully fetched and cached product: ${productData.name}`) return new Response( JSON.stringify(productData), { headers: { ...corsHeaders, 'Content-Type': 'application/json' } } ) } catch (error) { console.error('Error in product-lookup:', error) return new Response( JSON.stringify({ error: error instanceof Error ? error.message : 'Unknown error', barcode: null, name: null, }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 500 } ) } })