From 67f15ac9f2415c625ddf41af03cf864393effb74 Mon Sep 17 00:00:00 2001 From: Alexander James Phillips Date: Fri, 9 May 2025 22:22:40 +0100 Subject: [PATCH] feat: warn on async subscriber to onAuthStateChange --- src/GoTrueClient.ts | 8 ++++++++ test/GoTrueClient.test.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/GoTrueClient.ts b/src/GoTrueClient.ts index 609a9020..202debb1 100644 --- a/src/GoTrueClient.ts +++ b/src/GoTrueClient.ts @@ -1847,6 +1847,14 @@ export default class GoTrueClient { ): { data: { subscription: Subscription } } { + if (callback.constructor.name === 'AsyncFunction') { + console.warn( + 'Calling onAuthStateChange with an async function may cause a deadlock.' + + ' For a solution please see the docs: ' + + 'https://supabase.com/docs/reference/javascript/auth-onauthstatechange' + ) + } + const id: string = uuid() const subscription: Subscription = { id, diff --git a/test/GoTrueClient.test.ts b/test/GoTrueClient.test.ts index f08b96c2..39eeee69 100644 --- a/test/GoTrueClient.test.ts +++ b/test/GoTrueClient.test.ts @@ -814,6 +814,34 @@ describe('The auth client can signin with third-party oAuth providers', () => { }) }) + describe('Developers are warned if subscribing with an async function', () => { + const originalWarn = console.warn + let warnings: any[][] = [] + + beforeEach(() => { + console.warn = (...args: any[]) => { + console.log('WARN', ...args) + + warnings.push(args) + } + }) + + afterEach(() => { + console.warn = originalWarn + warnings = [] + }) + + test('Subscribing a non-async listener should not log a warning', async () => { + authSubscriptionClient.onAuthStateChange(() => console.log('onAuthStateChange was called')) + expect(warnings.length).toEqual(0) + }) + + test('Subscribing an async listener should log a warning', async () => { + authSubscriptionClient.onAuthStateChange(async () => console.log('onAuthStateChange was called')) + expect(warnings.length).toEqual(1) + }) + }) + describe('Sign Up Enabled', () => { test('User can sign up', async () => { const { email, password } = mockUserCredentials()