fix(realtime): setAuth é assíncrono — o await fecha a segunda janela

A dúvida residual era: "o conserto garante que `setAuth` seja CHAMADO, não que
tenha EFEITO sobre uma conexão que ainda não existe". O tipo de retorno
respondeu antes de qualquer experimento — `setAuth(token?): Promise<void>`.

Sem `await`, a flag `autenticou` virava true quando a CHAMADA saía, não quando o
token era APLICADO ao socket, e a promessa memoizada resolvia antes disso. Como
é essa promessa que os hooks esperam para assinar, o `subscribe` podia correr
com o socket ainda anônimo — e assinatura anônima com RLS por `auth.uid()`
recebe ZERO linhas, em silêncio, com o canal respondendo SUBSCRIBED.

Mesmo sintoma do defeito da memo, por outro caminho: lá a memo guardava a falha,
aqui a promessa resolvia cedo demais.

ISTO É CERCA, NÃO MEDIÇÃO — e é por isso que vale. A alternativa seria
instrumentar o hook para provocar a corrida, o que é mexer no mecanismo sob
teste; a orientação foi declarar a dúvida em vez de persegui-la, EXCETO se
existisse sinal de conexão que a removesse por construção. O `Promise` do
`setAuth` é esse sinal, e esperá-lo custa uma palavra.

O achado veio de ler a assinatura da API, não de rodar nada. A dúvida estava
escrita como limite conhecido e o limite acabou tendo conserto.

Board segue nascendo `authenticated` em duas rodadas com a assinatura apagada
entre elas. Os três unitários da memo seguem verdes.

typecheck 0 · lint 0 erros.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013dxBNZMjUzBx8xWs8DvGvP
This commit is contained in:
Rafael Melgaço
2026-07-25 15:09:59 -03:00
co-authored by Claude Opus 5
parent 416b1e2690
commit 02298924da
+17 -1
View File
@@ -41,6 +41,11 @@ export interface UseRealtimeChannelOpts {
* if (!res.ok) return → 401/500: memo FICAVA, setAuth nunca corria
* if (token) setAuth(token) → corpo sem token: memo FICAVA, idem
*
* E havia uma SEGUNDA janela, achada depois pelo tipo de retorno: `setAuth`
* é assíncrono, e chamá-lo sem `await` fazia a promessa memoizada resolver
* antes de o token estar no socket. Quem assinasse nesse intervalo assinava
* anônimo — o mesmo sintoma, por outro caminho.
*
* Ou seja: UM ÚNICO 401 transitório — sessão ainda estabelecendo, cookie em
* renovação — deixava TODOS os canais criados depois anônimos pelo resto
* daquele carregamento. E a recuperação estava escrita justamente para o
@@ -70,7 +75,18 @@ export function authenticateRealtime(supabase: ReturnType<typeof createClient>):
const body = (await res.json()) as { data?: { access_token?: string } };
const token = body.data?.access_token;
if (token) {
supabase.realtime.setAuth(token);
// ⚠️ O `await` NÃO É DECORATIVO: `setAuth` devolve `Promise<void>`.
//
// Sem ele, `autenticou` virava true quando a CHAMADA saía, não quando
// o token era APLICADO ao socket — e a promessa memoizada resolvia
// antes disso. Como quem assina espera essa promessa, o `subscribe`
// podia correr com o socket ainda anônimo, e uma assinatura anônima
// com RLS por `auth.uid()` recebe ZERO linhas em silêncio.
//
// A dúvida era: "o conserto garante que setAuth seja CHAMADO, não que
// tenha EFEITO". O tipo de retorno respondeu — havia mesmo uma janela,
// e esperar por ela custa uma palavra. É cerca, não medição.
await supabase.realtime.setAuth(token);
autenticou = true;
}
}