Files
pmc-funder-tool/netlify/functions/save-submission.js
T
2026-05-29 09:24:16 -04:00

98 lines
2.7 KiB
JavaScript

/**
* Netlify Function (Node runtime).
*
* Inserts a row into the Supabase `funder_data_submissions` table
* when the user submits the funder discovery form. Runs in parallel
* with the Anthropic agent stream and is intentionally independent of
* it — a Supabase failure must never block (or be observed by) the
* streaming brief.
*
* Environment variables (set in .env.local for local `netlify dev`,
* and in the Netlify UI for production):
* - SUPABASE_URL e.g. https://<project>.supabase.co
* - SUPABASE_SERVICE_ROLE_KEY service role key (server-side only)
*
* The service role key bypasses RLS, so this function must only be
* called from trusted server-side code (which it is — this endpoint
* is the only caller). Do NOT expose this key to the browser.
*/
export const handler = async (event) => {
if (event.httpMethod !== 'POST') {
return {
statusCode: 405,
body: JSON.stringify({ error: 'Method not allowed' }),
}
}
const SUPABASE_URL = process.env.SUPABASE_URL
const SUPABASE_SERVICE_ROLE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY
if (!SUPABASE_URL || !SUPABASE_SERVICE_ROLE_KEY) {
return {
statusCode: 500,
body: JSON.stringify({
error: 'Server is missing SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY',
}),
}
}
let payload
try {
payload = JSON.parse(event.body || '{}')
} catch {
return {
statusCode: 400,
body: JSON.stringify({ error: 'Invalid JSON body' }),
}
}
const row = {
name: payload.userName ?? null,
email: payload.userEmail ?? null,
station_name: payload.stationName ?? null,
station_location: payload.stationLocation ?? null,
station_website: payload.stationWebsite ?? null,
}
try {
const res = await fetch(
`${SUPABASE_URL.replace(/\/$/, '')}/rest/v1/funder_data_submissions`,
{
method: 'POST',
headers: {
apikey: SUPABASE_SERVICE_ROLE_KEY,
Authorization: `Bearer ${SUPABASE_SERVICE_ROLE_KEY}`,
'Content-Type': 'application/json',
Prefer: 'return=minimal',
},
body: JSON.stringify(row),
},
)
if (!res.ok) {
const text = await res.text()
console.error('Supabase insert failed', res.status, text)
return {
statusCode: 502,
body: JSON.stringify({
error: `Supabase insert failed: ${res.status} ${text}`,
}),
}
}
return {
statusCode: 204,
body: '',
}
} catch (err) {
console.error('Supabase request errored', err)
return {
statusCode: 500,
body: JSON.stringify({
error: `Supabase request errored: ${err?.message || String(err)}`,
}),
}
}
}