Problem
Neither client sets a timeout.
The object-storage client is built with credentials, bucket and endpoint only (apps/hocuspocus.server/src/lib/storage/storage.s3.ts:8-13). The Supabase clients set auth options only (apps/hocuspocus.server/src/lib/supabase.ts:13 and apps/hocuspocus.server/src/lib/supabase.ts:23-25). Neither file contains the string timeout.
A black-holed endpoint therefore holds the caller until the socket closes.
Token verification runs through the anon client (apps/hocuspocus.server/src/lib/auth.ts:86). A cache sits in front of it, const TOKEN_CACHE_TTL_MS = 60_000 (apps/hocuspocus.server/src/lib/auth.ts:52). So only a cache miss reaches Supabase. A miss can happen on the REST middleware path (apps/hocuspocus.server/src/api/middleware/auth.ts:29) and on the collaboration handshake (apps/hocuspocus.server/src/hocuspocus.server.ts:458). A stalled Supabase then stalls people signing in and reconnecting.
Two paths already bound themselves. The health probe sets .abortSignal(AbortSignal.timeout(2000)) (apps/hocuspocus.server/src/api/services/health.service.ts:73). The raw PostgREST helper supabaseRest sets signal: init?.signal ?? AbortSignal.timeout(SUPABASE_FETCH_TIMEOUT_MS) (apps/hocuspocus.server/src/api/utils/supabase.ts:21). That constant is const SUPABASE_FETCH_TIMEOUT_MS = 10_000 (apps/hocuspocus.server/src/api/utils/supabase.ts:8). Every other call made through the two clients carries no deadline.
What to do
Give both clients a default per-request deadline.
For Supabase, pass a global.fetch that attaches an AbortSignal.timeout. For object storage, wrap each call so it fails at a fixed deadline instead of at socket close.
Pick a bound that matches the one already in the tree. supabaseRest uses 10 s.
Acceptance
Problem
Neither client sets a timeout.
The object-storage client is built with credentials, bucket and endpoint only (
apps/hocuspocus.server/src/lib/storage/storage.s3.ts:8-13). The Supabase clients set auth options only (apps/hocuspocus.server/src/lib/supabase.ts:13andapps/hocuspocus.server/src/lib/supabase.ts:23-25). Neither file contains the stringtimeout.A black-holed endpoint therefore holds the caller until the socket closes.
Token verification runs through the anon client (
apps/hocuspocus.server/src/lib/auth.ts:86). A cache sits in front of it,const TOKEN_CACHE_TTL_MS = 60_000(apps/hocuspocus.server/src/lib/auth.ts:52). So only a cache miss reaches Supabase. A miss can happen on the REST middleware path (apps/hocuspocus.server/src/api/middleware/auth.ts:29) and on the collaboration handshake (apps/hocuspocus.server/src/hocuspocus.server.ts:458). A stalled Supabase then stalls people signing in and reconnecting.Two paths already bound themselves. The health probe sets
.abortSignal(AbortSignal.timeout(2000))(apps/hocuspocus.server/src/api/services/health.service.ts:73). The raw PostgREST helpersupabaseRestsetssignal: init?.signal ?? AbortSignal.timeout(SUPABASE_FETCH_TIMEOUT_MS)(apps/hocuspocus.server/src/api/utils/supabase.ts:21). That constant isconst SUPABASE_FETCH_TIMEOUT_MS = 10_000(apps/hocuspocus.server/src/api/utils/supabase.ts:8). Every other call made through the two clients carries no deadline.What to do
Give both clients a default per-request deadline.
For Supabase, pass a
global.fetchthat attaches anAbortSignal.timeout. For object storage, wrap each call so it fails at a fixed deadline instead of at socket close.Pick a bound that matches the one already in the tree.
supabaseRestuses 10 s.Acceptance