diff --git a/src/runtime/plugins/supabase.client.ts b/src/runtime/plugins/supabase.client.ts index 98fe21a02..654aa4628 100644 --- a/src/runtime/plugins/supabase.client.ts +++ b/src/runtime/plugins/supabase.client.ts @@ -1,5 +1,6 @@ import { createBrowserClient } from '@supabase/ssr' import type { Session } from '@supabase/supabase-js' +import { fetchWithRetry } from '../utils/fetch-retry' import { defineNuxtPlugin, useRuntimeConfig, useSupabaseSession, useSupabaseUser } from '#imports' export default defineNuxtPlugin({ @@ -12,6 +13,10 @@ export default defineNuxtPlugin({ ...clientOptions, cookieOptions, isSingleton: true, + global: { + fetch: fetchWithRetry, + ...clientOptions.global, + }, }) const currentSession = useSupabaseSession() diff --git a/src/runtime/plugins/supabase.server.ts b/src/runtime/plugins/supabase.server.ts index 7a6fe2b03..b987be23a 100644 --- a/src/runtime/plugins/supabase.server.ts +++ b/src/runtime/plugins/supabase.server.ts @@ -1,5 +1,6 @@ import { createServerClient, parseCookieHeader } from '@supabase/ssr' import { getHeader, setCookie } from 'h3' +import { fetchWithRetry } from '../utils/fetch-retry' import { defineNuxtPlugin, useRequestEvent, useRuntimeConfig, useSupabaseSession, useSupabaseUser } from '#imports' import type { CookieOptions } from '#app' @@ -24,6 +25,10 @@ export default defineNuxtPlugin({ ) => cookies.forEach(({ name, value, options }) => setCookie(event, name, value, options)), }, cookieOptions, + global: { + fetch: fetchWithRetry, + ...clientOptions.global, + }, }) // Initialize user and session states diff --git a/src/runtime/server/services/serverSupabaseClient.ts b/src/runtime/server/services/serverSupabaseClient.ts index c9f0c8c85..62e708bd7 100644 --- a/src/runtime/server/services/serverSupabaseClient.ts +++ b/src/runtime/server/services/serverSupabaseClient.ts @@ -1,6 +1,7 @@ import type { SupabaseClient } from '@supabase/supabase-js' import { createServerClient, parseCookieHeader, type CookieOptions } from '@supabase/ssr' import { getHeader, setCookie, type H3Event } from 'h3' +import { fetchWithRetry } from '../../utils/fetch-retry' import { useRuntimeConfig } from '#imports' import type { Database } from '#build/types/supabase-database' @@ -13,7 +14,7 @@ export const serverSupabaseClient = async (event: H3Event): Promis url, key, cookieOptions, - clientOptions: { auth = {} }, + clientOptions: { auth = {}, global = {} }, }, } = useRuntimeConfig().public @@ -30,6 +31,10 @@ export const serverSupabaseClient = async (event: H3Event): Promis ) => cookies.forEach(({ name, value, options }) => setCookie(event, name, value, options)), }, cookieOptions, + global: { + fetch: fetchWithRetry, + ...global, + }, }) } diff --git a/src/runtime/utils/fetch-retry.ts b/src/runtime/utils/fetch-retry.ts new file mode 100644 index 000000000..149ce713a --- /dev/null +++ b/src/runtime/utils/fetch-retry.ts @@ -0,0 +1,20 @@ +export async function fetchWithRetry(req: RequestInfo | URL, init?: RequestInit): Promise { + const retries = 3 + for (let attempt = 1; attempt <= retries; attempt++) { + try { + return await fetch(req, init) + } + catch (error) { + // Don't retry if it's an abort + if (init?.signal?.aborted) { + throw error + } + if (attempt === retries) { + console.error(`Error fetching request ${req}`, error, init) + throw error + } + console.warn(`Retrying fetch attempt ${attempt + 1} for request: ${req}`) + } + } + throw new Error('Unreachable code') +}