From 5d975278eeee828cac42e7de83883ca5fb8aa0f2 Mon Sep 17 00:00:00 2001 From: David Roizenman Date: Sun, 14 Jun 2026 23:25:09 -0700 Subject: [PATCH 1/3] fix(supabase): avoid dropping realtime auth to manual mode on client init --- .../core/supabase-js/src/SupabaseClient.ts | 7 ++--- .../test/unit/SupabaseClient.test.ts | 26 ++++++++----------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/packages/core/supabase-js/src/SupabaseClient.ts b/packages/core/supabase-js/src/SupabaseClient.ts index a38798d63b..968d472f1f 100644 --- a/packages/core/supabase-js/src/SupabaseClient.ts +++ b/packages/core/supabase-js/src/SupabaseClient.ts @@ -370,11 +370,8 @@ export default class SupabaseClient< ...settings.realtime, }) if (this.accessToken) { - // Start auth immediately to avoid race condition with channel subscriptions - // Wrap Promise to avoid Firefox extension cross-context Promise access errors - Promise.resolve(this.accessToken()) - .then((token) => this.realtime.setAuth(token)) - .catch((e) => console.warn('Failed to set initial Realtime auth token:', e)) + // Start auth immediately to avoid a race with channel subscriptions + this.realtime.setAuth() } this.rest = new PostgrestClient(new URL('rest/v1', baseUrl).href, { diff --git a/packages/core/supabase-js/test/unit/SupabaseClient.test.ts b/packages/core/supabase-js/test/unit/SupabaseClient.test.ts index d493923bdb..ebea4b7d8d 100644 --- a/packages/core/supabase-js/test/unit/SupabaseClient.test.ts +++ b/packages/core/supabase-js/test/unit/SupabaseClient.test.ts @@ -263,21 +263,21 @@ describe('SupabaseClient', () => { jest.clearAllMocks() }) - test('should automatically call setAuth() when accessToken option is provided', async () => { + test('should automatically call setAuth() in callback mode when accessToken option is provided', async () => { const customToken = 'custom-jwt-token' const customAccessTokenFn = jest.fn().mockResolvedValue(customToken) const client = createClient(URL, KEY, { accessToken: customAccessTokenFn }) - const setAuthSpy = jest.spyOn(client.realtime, 'setAuth') - // Wait for the constructor's async operation to complete - await Promise.resolve() + // Flush microtask queue to wait for constructor setting auth + await new Promise((resolve) => setTimeout(resolve)) - expect(setAuthSpy).toHaveBeenCalledWith(customToken) + // Realtime acquires auth token without dropping to manual mode expect(customAccessTokenFn).toHaveBeenCalled() + expect(client.realtime.accessTokenValue).toBe(customToken) + expect((client.realtime as any)._isManualToken()).toBe(false) // Clean up - setAuthSpy.mockRestore() client.realtime.disconnect() }) @@ -296,24 +296,20 @@ describe('SupabaseClient', () => { }) test('should handle errors gracefully when accessToken callback fails', async () => { - const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}) const error = new Error('Token fetch failed') const failingAccessTokenFn = jest.fn().mockRejectedValue(error) const client = createClient(URL, KEY, { accessToken: failingAccessTokenFn }) - // Wait for the promise to reject and warning to be logged - await Promise.resolve() - await Promise.resolve() + // Flush microtask queue to wait for constructor setting auth + await new Promise((resolve) => setTimeout(resolve)) - expect(consoleWarnSpy).toHaveBeenCalledWith( - 'Failed to set initial Realtime auth token:', - error - ) + expect(failingAccessTokenFn).toHaveBeenCalled() expect(client).toBeDefined() expect(client.realtime).toBeDefined() + // Stays in callback mode so a later setAuth() retries the callback. + expect((client.realtime as any)._isManualToken()).toBe(false) - consoleWarnSpy.mockRestore() client.realtime.disconnect() }) From 7139edcf4f00b16379ee696a07f45cc7a5f0fd4e Mon Sep 17 00:00:00 2001 From: David Roizenman Date: Sat, 20 Jun 2026 16:41:23 -0700 Subject: [PATCH 2/3] stray period in comment --- packages/core/supabase-js/test/unit/SupabaseClient.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/supabase-js/test/unit/SupabaseClient.test.ts b/packages/core/supabase-js/test/unit/SupabaseClient.test.ts index ebea4b7d8d..c34f6ec942 100644 --- a/packages/core/supabase-js/test/unit/SupabaseClient.test.ts +++ b/packages/core/supabase-js/test/unit/SupabaseClient.test.ts @@ -307,7 +307,7 @@ describe('SupabaseClient', () => { expect(failingAccessTokenFn).toHaveBeenCalled() expect(client).toBeDefined() expect(client.realtime).toBeDefined() - // Stays in callback mode so a later setAuth() retries the callback. + // Stays in callback mode so a later setAuth() retries the callback expect((client.realtime as any)._isManualToken()).toBe(false) client.realtime.disconnect() From 51b3648901c6a5e3624e352523819299cd003fb9 Mon Sep 17 00:00:00 2001 From: David Roizenman Date: Wed, 29 Jul 2026 23:56:53 -0700 Subject: [PATCH 3/3] catch setauth errors --- packages/core/supabase-js/src/SupabaseClient.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/supabase-js/src/SupabaseClient.ts b/packages/core/supabase-js/src/SupabaseClient.ts index b907f3376a..e84f44b047 100644 --- a/packages/core/supabase-js/src/SupabaseClient.ts +++ b/packages/core/supabase-js/src/SupabaseClient.ts @@ -386,7 +386,9 @@ export default class SupabaseClient< }) if (this.accessToken) { // Start auth immediately to avoid a race with channel subscriptions - this.realtime.setAuth() + this.realtime + .setAuth() + .catch((e) => console.warn('Failed to set initial Realtime auth token:', e)) } this.rest = new PostgrestClient(new URL('rest/v1', baseUrl).href, {