PostgREST client picks transport by AUTH_PROVIDER; two small resilience fixes

Commit `5d6f529c` makes `lib/supabase.ts` branch on `AUTH_PROVIDER` at startup to select one of three request behaviors: standard supabase-js for hosted Supabase, a fetch wrapper that strips the `/rest/v1` prefix for local and entra modes, and header stripping in entra mode where PostgREST runs without a JWT secret and rejects `Authorization` headers.

infrastructureintegration

Maintained by Allen Morgan · verified on MikeWatch

The core problem is that supabase-js hard-codes /rest/v1 in all request paths, which is correct for hosted Supabase but breaks when SUPABASE_URL points directly at PostgREST. The fix is a postgrestFetchWrapper that intercepts every request from the supabase-js client and rewrites the path. The wrapper is built around new Request(input, init) to handle both call shapes supabase-js uses internally.

In entra mode the wrapper also strips Authorization and apikey headers before the request leaves the process. The deployed PostgREST runs with PGRST_DB_ANON_ROLE=service_role and no jwt-secret, so it rejects requests that carry an Authorization header. Trust in that setup comes from network isolation - nothing outside the Container Apps Environment can reach PostgREST directly. In local mode the headers are kept because PostgREST validates the JWT against PGRST_JWT_SECRET.

Two smaller changes ride along in the same commit. routes/chat.ts now falls back to the first ~60 characters of the user message when LLM-driven title generation fails, so a failed title-gen doesn't surface as an error. lib/downloadTokens.ts adds a startup-time check: in NODE_ENV=production it throws if DOWNLOAD_SIGNING_SECRET is missing or under 16 characters, with a clear message explaining why - previously a missing secret silently fell back to a hardcoded string.

So what The chat-title fallback and the `DOWNLOAD_SIGNING_SECRET` hard-fail in production are both standalone improvements worth considering. The header-stripping fetch wrapper only matters if you're running PostgREST without Supabase's gateway layer.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

1 commit from Altien/mikeOssAzure, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
5d6f529c feat(supabase): provider-aware PostgREST client + chat title fallback Allen Morgan 2026-05-08 ↗ GitHub
commit body
  * lib/supabase.ts now picks one of three transports based on
    AUTH_PROVIDER:

      supabase  - default supabase-js, hits hosted Supabase /rest/v1
      local     - supabase-js with a fetch wrapper that strips the
                  /rest/v1 prefix so SUPABASE_URL can point at PostgREST
                  directly (no Caddy required for the local docker stack)
      entra     - same prefix-strip plus Authorization/apikey header
                  removal, since the deployed PostgREST runs without
                  jwt-secret and refuses requests carrying Authorization.
                  Trust comes from network isolation: only the
                  Container Apps internal ingress can reach PostgREST.

    The "supabase" function name is now historical - for everything but
    the supabase branch this is a generic PostgREST client.

  * routes/chat.ts: title generation is cosmetic, so an LLM failure (no
    provider configured, AOAI deployment unreachable, etc.) now falls
    back to the first ~60 chars of the user message instead of failing
    the entire request.  Errors still log with context.

  * lib/downloadTokens.ts: hard-fail on missing DOWNLOAD_SIGNING_SECRET
    in production mode.  Same dev-mode fallback as before.

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-197.md from inside the repo you want the changes in.

⬇ Download capture-thread-197.md