Created
January 21, 2025 22:41
-
-
Save bmorrisondev/a8c7910b8d2e02e777146223e6366930 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Follow this setup guide to integrate the Deno language server with your editor: | |
| // https://deno.land/manual/getting_started/setup_your_environment | |
| // This enables autocomplete, go to definition, etc. | |
| // Setup type definitions for built-in Supabase Runtime APIs | |
| import "jsr:@supabase/functions-js/edge-runtime.d.ts" | |
| import { createClient } from 'https://esm.sh/@supabase/[email protected]' | |
| console.log("Hello from Functions!") | |
| interface WebhookEvent { | |
| data: { | |
| id: string; | |
| first_name?: string; | |
| last_name?: string; | |
| name?: string; | |
| image_url?: string; | |
| email_addresses?: Array<{ | |
| email_address: string; | |
| verification: { | |
| status: string; | |
| }; | |
| }>; | |
| primary_email_address_id?: string; | |
| public_metadata?: Record<string, unknown>; | |
| unsafe_metadata?: Record<string, unknown>; | |
| created_at: number; | |
| updated_at: number; | |
| // Organization data | |
| organization?: { | |
| id: string; | |
| name: string; | |
| created_at: number; | |
| updated_at: number; | |
| }; | |
| // Public user data for org membership | |
| public_user_data?: { | |
| user_id: string; | |
| first_name?: string; | |
| last_name?: string; | |
| image_url?: string; | |
| email_address?: string; | |
| }; | |
| }; | |
| object: 'event'; | |
| type: string; | |
| } | |
| Deno.serve(async (req) => { | |
| // Verify webhook signature | |
| const webhookSecret = Deno.env.get('CLERK_WEBHOOK_SECRET') | |
| if (!webhookSecret) { | |
| return new Response('Webhook secret not configured', { status: 500 }) | |
| } | |
| // Get the headers | |
| const svix_id = req.headers.get('svix-id') | |
| const svix_timestamp = req.headers.get('svix-timestamp') | |
| const svix_signature = req.headers.get('svix-signature') | |
| // If there are no headers, error out | |
| if (!svix_id || !svix_timestamp || !svix_signature) { | |
| return new Response('Error occured -- no svix headers', { status: 400 }) | |
| } | |
| // Get the body | |
| const payload = await req.json() | |
| const body = JSON.stringify(payload) | |
| // Create supabase client | |
| const supabaseUrl = Deno.env.get('SUPABASE_URL') | |
| const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') | |
| if (!supabaseUrl || !supabaseServiceKey) { | |
| return new Response('Supabase credentials not configured', { status: 500 }) | |
| } | |
| const supabase = createClient(supabaseUrl, supabaseServiceKey) | |
| // Handle the webhook | |
| const event = payload as WebhookEvent | |
| switch (event.type) { | |
| case 'user.created': { | |
| // Handle user creation | |
| const { data: user, error } = await supabase | |
| .from('users') | |
| .insert([ | |
| { | |
| id: event.data.id, | |
| first_name: event.data.first_name, | |
| last_name: event.data.last_name, | |
| avatar_url: event.data.image_url, | |
| created_at: new Date(event.data.created_at).toISOString(), | |
| updated_at: new Date(event.data.updated_at).toISOString(), | |
| }, | |
| ]) | |
| .select() | |
| .single() | |
| if (error) { | |
| console.error('Error creating user:', error) | |
| return new Response(JSON.stringify({ error: error.message }), { status: 500 }) | |
| } | |
| return new Response(JSON.stringify({ user }), { status: 200 }) | |
| } | |
| case 'user.updated': { | |
| // Handle user update | |
| const { data: user, error } = await supabase | |
| .from('users') | |
| .update({ | |
| first_name: event.data.first_name, | |
| last_name: event.data.last_name, | |
| avatar_url: event.data.image_url, | |
| updated_at: new Date(event.data.updated_at).toISOString(), | |
| }) | |
| .eq('id', event.data.id) | |
| .select() | |
| .single() | |
| if (error) { | |
| console.error('Error updating user:', error) | |
| return new Response(JSON.stringify({ error: error.message }), { status: 500 }) | |
| } | |
| return new Response(JSON.stringify({ user }), { status: 200 }) | |
| } | |
| case 'organization.created': { | |
| // Handle user update | |
| const { data, error } = await supabase | |
| .from('organizations') | |
| .create({ | |
| id: event.data.id, | |
| name: event.data.name, | |
| updated_at: new Date(event.data.updated_at).toISOString(), | |
| }) | |
| .select() | |
| .single() | |
| if (error) { | |
| console.error('Error updating owner:', error) | |
| return new Response(JSON.stringify({ error: error.message }), { status: 500 }) | |
| } | |
| return new Response(JSON.stringify({ data }), { status: 200 }) | |
| } | |
| case 'organization.updated': { | |
| const { data, error } = await supabase | |
| .from('owners') | |
| .update({ | |
| name: event.data.name, | |
| updated_at: new Date(event.data.updated_at).toISOString(), | |
| }) | |
| .eq('id', event.data.id) | |
| .select() | |
| .single() | |
| if (error) { | |
| console.error('Error updating owner:', error) | |
| return new Response(JSON.stringify({ error: error.message }), { status: 500 }) | |
| } | |
| return new Response(JSON.stringify({ data }), { status: 200 }) | |
| } | |
| case 'organizationMembership.created': { | |
| const { data, error } = await supabase | |
| .from('members') | |
| .insert([ | |
| { | |
| id: event.data.id, | |
| user_id: event.data.public_user_data?.user_id, | |
| organization_id: event.data.organization?.id, | |
| created_at: new Date(event.data.created_at).toISOString(), | |
| updated_at: new Date(event.data.updated_at).toISOString(), | |
| }, | |
| ]) | |
| .select() | |
| .single() | |
| if (error) { | |
| console.error('Error updating member:', error) | |
| return new Response(JSON.stringify({ error: error.message }), { status: 500 }) | |
| } | |
| return new Response(JSON.stringify({ data }), { status: 200 }) | |
| } | |
| case 'organizationMembership.updated': { | |
| const { data, error } = await supabase | |
| .from('members') | |
| .update({ | |
| user_id: event.data.public_user_data?.user_id, | |
| organization_id: event.data.organization?.id, | |
| updated_at: new Date(event.data.updated_at).toISOString(), | |
| }) | |
| .eq('id', event.data.id) | |
| .select() | |
| .single() | |
| if (error) { | |
| console.error('Error updating member:', error) | |
| return new Response(JSON.stringify({ error: error.message }), { status: 500 }) | |
| } | |
| return new Response(JSON.stringify({ data }), { status: 200 }) | |
| } | |
| default: { | |
| // Unhandled event type | |
| console.log('Unhandled event type:', JSON.stringify(event, null, 2)) | |
| return new Response(JSON.stringify({ success: true }), { status: 200 }) | |
| } | |
| } | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment