Created
December 21, 2023 06:16
-
-
Save susemeee/3ee8c9b3b0ff7a56ec5c739d7b0a99bf to your computer and use it in GitHub Desktop.
supabase-fetch-override-workaround
This file contains 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
import { Database } from '@/lib/supabase-types' | |
import { createClient } from '@supabase/supabase-js' | |
export const SUPABASE_NEXTJS_CACHE_TAG = "supabase" | |
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL! | |
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! | |
export const client = createClient<Database>( | |
supabaseUrl, | |
supabaseKey, | |
) | |
export default client | |
const nextFetchExtras: NextFetchRequestConfig = { | |
tags: [SUPABASE_NEXTJS_CACHE_TAG], | |
} | |
type SupabaseQueryType = ReturnType<ReturnType<typeof client["from"]>["select"]> | | |
ReturnType<ReturnType<typeof client["rpc"]>["select"]> | |
export async function supabaseNextCompatFetch(arg: SupabaseQueryType, tags?: string[]) { | |
/** | |
// @ts-ignore | |
arg.fetch = async (a0: any, a1: any) => { | |
// @ts-ignore | |
const token = await client._getAccessToken() ?? supabaseKey | |
// @ts-ignore | |
const { url, headers, method, body, signal, isMaybeSingle, shouldThrowOnError } = arg | |
headers['apikey'] = supabaseKey | |
headers['Authorization'] = `Bearer ${token}` | |
return fetch(a0, a1) | |
} | |
return arg | |
*/ | |
/** | |
* "@supabase/postgrest-js": "^1.8.5" | |
* https://github.com/supabase/postgrest-js/blob/5e7dbdcdc57bdd2f3a57c2aa65eff1c941ab1ec6/src/PostgrestBuilder.ts#L76 | |
*/ | |
// @ts-ignore | |
const token = await client._getAccessToken() ?? supabaseKey | |
// @ts-ignore | |
const { url, headers, method, body, signal, isMaybeSingle, shouldThrowOnError, schema } = arg | |
headers['apikey'] = supabaseKey | |
headers['Authorization'] = `Bearer ${token}` | |
// https://postgrest.org/en/stable/api.html#switching-schemas | |
if (schema === undefined) { | |
// skip | |
} else if (['GET', 'HEAD'].includes(method)) { | |
headers['Accept-Profile'] = schema | |
} else { | |
headers['Content-Profile'] = schema | |
} | |
if (method !== 'GET' && method !== 'HEAD') { | |
headers['Content-Type'] = 'application/json' | |
} | |
return fetch(url.toString(), { headers, method, body: JSON.stringify(body), signal, next: { ...nextFetchExtras, tags: tags ?? nextFetchExtras.tags } }) | |
.then(async (res) => { | |
let error = null | |
let data = null | |
let count: number | null = null | |
let status = res.status | |
let statusText = res.statusText | |
if (res.ok) { | |
if (method !== 'HEAD') { | |
const body = await res.text() | |
if (body === '') { | |
// Prefer: return=minimal | |
} else if (headers['Accept'] === 'text/csv') { | |
data = body | |
} else if ( | |
headers['Accept'] && | |
headers['Accept'].includes('application/vnd.pgrst.plan+text') | |
) { | |
data = body | |
} else { | |
data = JSON.parse(body) | |
} | |
} | |
const countHeader = headers['Prefer']?.match(/count=(exact|planned|estimated)/) | |
const contentRange = res.headers.get('content-range')?.split('/') | |
if (countHeader && contentRange && contentRange.length > 1) { | |
count = parseInt(contentRange[1]) | |
} | |
// Temporary partial fix for https://github.com/supabase/postgrest-js/issues/361 | |
// Issue persists e.g. for `.insert([...]).select().maybeSingle()` | |
if (isMaybeSingle && method === 'GET' && Array.isArray(data)) { | |
if (data.length > 1) { | |
error = { | |
// https://github.com/PostgREST/postgrest/blob/a867d79c42419af16c18c3fb019eba8df992626f/src/PostgREST/Error.hs#L553 | |
code: 'PGRST116', | |
details: `Results contain ${data.length} rows, application/vnd.pgrst.object+json requires 1 row`, | |
hint: null, | |
message: 'JSON object requested, multiple (or no) rows returned', | |
} | |
data = null | |
count = null | |
status = 406 | |
statusText = 'Not Acceptable' | |
} else if (data.length === 1) { | |
data = data[0] | |
} else { | |
data = null | |
} | |
} | |
} else { | |
const body = await res.text() | |
try { | |
error = JSON.parse(body) | |
// Workaround for https://github.com/supabase/postgrest-js/issues/295 | |
if (Array.isArray(error) && res.status === 404) { | |
data = [] | |
error = null | |
status = 200 | |
statusText = 'OK' | |
} | |
} catch { | |
// Workaround for https://github.com/supabase/postgrest-js/issues/295 | |
if (res.status === 404 && body === '') { | |
status = 204 | |
statusText = 'No Content' | |
} else { | |
error = { | |
message: body, | |
} | |
} | |
} | |
if (error && isMaybeSingle && error?.details?.includes('0 rows')) { | |
error = null | |
status = 200 | |
statusText = 'OK' | |
} | |
if (error && shouldThrowOnError) { | |
throw error | |
} | |
} | |
const postgrestResponse = { | |
error, | |
data, | |
count, | |
status, | |
statusText, | |
} | |
return postgrestResponse | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment