Skip to content

chore: production deploy - #7452

Open
supabase-cli-releaser[bot] wants to merge 86 commits into
mainfrom
develop
Open

supabase-cli-releaser[bot] wants to merge 86 commits into
mainfrom
develop

Conversation

@supabase-cli-releaser

Copy link
Copy Markdown
Contributor

pamelachia and others added 22 commits November 2, 2026 12:08
`branches create`, `vanity-subdomains activate`, and `vanity-subdomains
check-availability` ran an entitlements lookup (get project, then get
organization entitlements) after any 4xx without the
`entitlement_required` envelope. The Management API already returns that
envelope on all three gates, so the lookup only ran for errors unrelated
to the plan: two extra requests, and on an org without the feature, an
upgrade hint and a `plan_limit` classification for an unrelated error
such as a validation failure.

I removed the lookup and its permission declarations at those three
commands. The CLI still prints the upgrade hint from the envelope on
gated denials and fires `cli_upgrade_suggested` for `branches create`
and `vanity-subdomains activate` (`check-availability` still suppresses
the event), unchanged since #7271.

**Note:** I left `branches update` and the `sso` commands on the lookup
for now: the SAML routes return no envelope yet, and I haven't confirmed
that the persistent-branch gate on `branches update` returns one.

## Linear
- part of GROWTH-1050
## TL;DR

fixes `supabase start` sitting about 10s on docker's first health check
when the services are already up.

## whats improved/fixed?

docker runs a container's first health check one full interval after it
starts, and our interval is 10s.

so `supabase start` kept waiting on that check even when everything was
ready sooner.

a restart with the issue's excludes went from about 12.8s to 5.2s.
a full stack restart went from about 14s to 8s `db start` and `db reset`
get the same.

## how?

containers with a docker healthcheck now get `--health-start-interval
1s` and a 10s start period when `docker version` shows API 1.44 or newer
for the client binary, the client in use, and the daemon, so the first
check runs about 1s in and the interval stays 10s after.

kong's check lived only in its image, so its spec now sets the same
`kong health` check and gets those flags too.

> [!NOTE]
> on engines without the flag (docker below API 1.44, podman) containers
keep the 10s first check.

## ref:

- closes: #7427
)

Follow-up to #7412.

Block-scoped workloads started one stack per block of five launches, so
a ten-run workload gave each build only two stack sessions. Launches in
one block share a stack session, so session-to-session spread could push
the branch median outside the base range, and an A/A run (same CLI code
as base and branch) was flagged as slower or faster.

- Blocks are now two launches, so each build gets five stack sessions at
ten runs, and each measured launch records its block index in the
report.
- With at least three paired blocks, the block is the unit of evidence.
The median of the per-block deltas must clear the existing 5 percent and
5 ms floor, a strict majority of blocks must move the same way past that
floor, and the median delta must exceed 1.5 times the larger
interquartile range of the two builds' block medians. One odd block
cannot create or hide a verdict, and mixed-sign blocks read as within
noise.
- Run-scoped workloads keep the existing rule (the branch median outside
the base min-max range) and also need the median delta to exceed 1.5
times the larger interquartile range of the two builds' launches, so a
wide spread reads as noise.
- `estimatedSeconds` for block-scoped workloads is rescaled for the
extra stack sessions, and `tracing-monitoring.md` describes the new
rule.

False positives may not be entirely eliminated. A follow-up could allow
re-running one or more chosen workloads, so a reported regression can be
confirmed without re-running the whole benchmark.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
)

The local container inputs precedence goldens recorded the default
Postgres image tag, so every Postgres bump PR (e.g. #7408)
failed integration tests until the goldens were regenerated by hand.

The test now redacts the current default database image as
`<DEFAULT_POSTGRES_IMAGE>`, keeping the goldens focused on config
precedence.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…7443)

The Management API spec now describes the ESZIP update-function body
through a shared component that carries a `description` and
`contentEncoding`. The generator only rewrote a bare `{ format: "binary"
}` annotation to `BinaryInput`, so this body regenerated as
`Schema.String` and rejected `Uint8Array`/`ArrayBuffer`/`Blob` uploads
(breaking `functions deploy`).

The sanitizer now reduces binary string schemas to their type and
format, so they keep generating as `BinaryInput`. Generated output on
`develop` is unchanged; this unblocks the API sync in
#7418, which still needs its v2
PostgREST config fixture updated for the new
`db_pool_max_lifetime`/`db_pool_max_idletime` fields.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This bumps postgres from 17.11.0.011-r0 to 17.11.0.016-r0.


https://github.com/supabase/slim-services/releases/tag/postgres-17.11.0.016-r0

Planned after supabase/slim-services published 17.11.0.015-orioledb-r0.
This branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
This PR was automatically created to sync the generated `@supabase/api`
package with the latest Management API OpenAPI document.

Changes were detected in the upstream OpenAPI documents exposed by
`https://api.supabase.com/api/v1-json` and
`https://api.supabase.com/api/v2-json`.

---------

Co-authored-by: jgoux <1443499+jgoux@users.noreply.github.com>
Co-authored-by: avallete <andrew.valleteau@supabase.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
This bumps postgres from 17.11.0.016-r0 to 17.11.0.017-r0.


https://github.com/supabase/slim-services/releases/tag/postgres-17.11.0.017-r0

Planned after supabase/slim-services published 17.11.0.017-orioledb-r0.
This branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps postgres from 15.19.0.016-r0 to 15.19.0.017-r0.


https://github.com/supabase/slim-services/releases/tag/postgres-15.19.0.017-r0

Planned after supabase/slim-services published 17.11.0.017-orioledb-r0.
This branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## TL;DR

The live branch helper now re-creates a branch once when the platform
drops TLS while setting the branch password, the same way it handles a
57P01 database restart.

- `apps/cli/src/commands/branches/get/get.live.test.ts › gets a preview
branch by name`: `branches create` failed with `400: Failed to update
password: Client network socket disconnected before secure TLS
connection was established`. This is a transient platform rejection
during create, like the 57P01 restart from #7256, but the helper only
re-issued the create for 57P01. The helper's transient-rejection matcher
now also covers this documented TLS drop, so it runs the same single
clear-and-recreate. A second rejection still fails. `create.live` uses
the same helper and gets the fix too.

## ref

spotted in:
-
https://github.com/supabase/cli/actions/runs/40170147136/job/121099157809
(develop)
-
https://github.com/supabase/cli/actions/runs/40170152974/job/121099176450
(main)

---
_Generated by [Claude
Code](https://claude.ai/code/session_014y76TaNM2eKGdpmiMQXWqu)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
## TL;DR

The Realtime, pg-meta and Studio catalog test hung on Podman without
saying where. It now fails before the test timeout, naming the service
and phase that stalled and that service's output.

- `Realtime.integration.test.ts › serves Realtime, pg-meta, and Studio
against the owned database`: on Podman, the test hit the 120s test
timeout with only the generator start frame as a clue. The test runs
four services in sequence (database, Realtime, pg-meta, Studio), each
with a recipe, start, readiness and HTTP step, so a stall anywhere
looked the same. The cause is still unknown, so this change is a
diagnostic. The scoped body now runs under a 110s guard. Each step
records its phase, and each recipe's launch output is collected. A stall
fails with `CatalogStallError` naming the service and phase in progress
(including stop and root cleanup) and the last part of that service's
output.

## ref

spotted in:
-
https://github.com/supabase/cli/actions/runs/40530528881/job/122281757547

---
_Generated by [Claude
Code](https://claude.ai/code/session_01MBEk1PCdaXDCUPR16M9Ria)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
## TL;DR
The native owner-logs test no longer pays a private cold artifact fetch
inside its timeout, and a stall now names the step that hung.

- `Owner.logs.integration.test.ts › persists native output, serves
history and follow, and deletes it on destroy`: the test hit the 30s
test timeout while starting native Mailpit. The vitest frame pointed at
the `openOwner` helper, not the stalled step. This file kept native
artifacts in an OS temp cache (`$TMPDIR/supabase-stack-artifacts`) that
no other suite shares, so on a runner without a warm temp dir its first
native test fetched Mailpit inside the test timeout (the next native
test in the file then took ~12s instead of under 1s). The file now uses
the shared test artifact cache (`testArtifactCacheRoot`) like the other
stack integration suites. The create, start (artifact preparation),
readiness, first-follow and history steps also run under a 25s guard
that fails with `NativeMailStallError`, naming the step, the instance id
and Mailpit's persisted output, so a remaining stall points at its
phase.

## ref
spotted in:
https://github.com/supabase/cli/actions/runs/41383389524/job/125078843228
(green on the same SHA:
https://github.com/supabase/cli/actions/runs/41383048926/job/125077793411)

---
_Generated by [Claude
Code](https://claude.ai/code/session_01MBEk1LVZyNoX4Zg9Nd5ZMM)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
This bumps storage from v1.88.0-r0 to v1.89.1-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.89.1-r0

Planned after supabase/slim-services published v1.89.1-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## TL;DR

re-issues the live `db reset` cleanup once when the platform restarts
the database, so one dropped connection can't leave a migration behind
for the next file

- `db reset` live failed in cleanup with `FATAL: terminating connection
due to administrator command (SQLSTATE 57P01)` from the pooler on
connect. the cleanup reset never ran, so the test's migration stayed in
the shared project's history and the following `db push` live file
failed with `Remote migration versions not found`. the `db reset` and
`db push` cleanups now go through `resetLiveDatabase`, which re-issues
the reset once on a platform database restart (the same rule `branches
create` already uses) and names the re-issue when it fails again

## ref

- spotted in: [failing
job](https://github.com/supabase/cli/actions/runs/41176803525/job/124465943942)
[green same
SHA](https://github.com/supabase/cli/actions/runs/41015125746)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01MBEk1LFBnaQgPd2VvJLo4X

Co-authored-by: Claude <noreply@anthropic.com>
…7288)

## TL;DR

Two stack integration tests failed because of runner state, not because
of the code under test.

- `Network.integration.test.ts › a pinned shared listener keeps its
reservation until its last route closes`: on Windows, the bind failed as
a foreign port conflict on 1801. The random pinned port landed on a port
that a Windows runner service holds, and the static held-port list
cannot anticipate every such port. `pinnedPort` now draws again until no
listener answers the drawn loopback port and the bind's own vacancy
guard (`Ports.probeVacant`) accepts it. This replaces the static list.
- `DockerDatabaseStorage.integration.test.ts › round-trips PostgreSQL 15
data with its catalog image`: the pull failed with `toomanyrequests`
after all pull retries. GHCR rate-limited the runner for longer than the
pull backoff, and the tests had no image mirror, unlike the stack's
production wiring. Three changes give the tests the same ECR fallback
the stack uses:
- The tests' container runtimes and the spawned helper-owner fixture now
use `slimImageMirrors`.
  - The direct engine runs use the reference the runtime resolved.
  - The test that checks a custom mirror keeps its explicit mirror.

## ref

spotted in:
-
https://github.com/supabase/cli/actions/runs/39757673300/job/119753742485
-
https://github.com/supabase/cli/actions/runs/39812209412/job/119941209064

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01XrrxbNdkjLwsEeJJiJvGs8

---------

Co-authored-by: Claude <noreply@anthropic.com>
## TL;DR

The Mailpit launch test hung on Podman without saying where. It now
fails within its timeout, naming the phase that stalled and Mailpit's
output. The detached stall guard it uses is now one shared test helper,
`failOnStall`, which the Realtime and native owner-logs tests also use.

- `Mail.integration.test.ts › launches the real Mailpit recipe and
serves its HTTP endpoint`: on Podman, the test hit the 30s test timeout
with no diagnostic. The error frame pointed at `sendTestEmail`, but this
test never sends mail, so that frame is misleading. The test waits on
start, readiness and a `/readyz` request. Container readiness may wait
up to 60s, longer than the test timeout, and the `/readyz` request has
no bound. So a stall in any of the three looked the same. The whole test
scope now runs under one 25s guard inside the 30s test timeout, and a
`Ref` tracks the current phase. The test also collects the recipe's log
stream, so a stall fails with `MailStallError` naming the phase and
showing Mailpit's output so far.
- `packages/stack/tests/stall-guard.ts` adds `failOnStall(duration,
onStall)`. It joins the guarded effect from a detached fiber, so the
stall error surfaces at the deadline instead of waiting for teardown,
and it interrupts the stalled fiber in the background so scoped cleanup
still runs. `Mail`, `Realtime` (#7359) and `Owner.logs` (#7434)
integration tests now share it instead of carrying three copies; each
keeps its own stall message.

## ref

spotted in:
-
https://github.com/supabase/cli/actions/runs/39920135558/job/120303098411

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude <noreply@anthropic.com>
This adds postgres 17.11.0.017-orioledb-r0 as a new release line.


https://github.com/supabase/slim-services/releases/tag/postgres-17.11.0.017-orioledb-r0

Planned after supabase/slim-services published 17.11.0.017-orioledb-r0.
This branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps storage from v1.89.1-r0 to v1.89.2-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.89.2-r0

Planned after supabase/slim-services published v1.89.2-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.151.3-r0 to v2.151.4-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.151.4-r0

Planned after supabase/slim-services published v2.151.4-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## TL;DR

folds the effect lint into `pnpm lint:check`, so one `.oxlintrc.json`
drives editors, agents and CI

## whats introduced?

- `.oxlintrc.json` extends the `@effect/tsgo` recommended preset, and
`.oxlintrc.effect.json` and the `lint:effect:*` scripts go away
- `.github/scripts`, the npm launcher shim, compute stack templates and
the generated API contracts move to `ignorePatterns`, so they leave the
repo lint entirely
- `lint:fix` applies suggestions, and `fix:all` runs knip, lint and
format in order so fixes never race

## ref

- closes: CLI-2899 & CLI-2407
… (#7394)

## TL;DR

adds `SUPABASE_API_MAX_RETRIES` so automation can cap management api
retries, where `0` sends each request once.

## whats introduced?

the new env var sets the retry count on every management api client the
cli builds
 login and `services` included.
`functions deploy` caps its own retry loops at that value and keeps
honouring rate limit headers, and a duplicated create still becomes an
update even at `0`. an invalid value stops the command before any
request, and leaving it unset keeps today's behavior...

```mermaid
flowchart TD
  env["SUPABASE_API_MAX_RETRIES"] --> parse{"CommandSettings.load"}
  parse -- "unset or empty" --> none["none: today's behaviour"]
  parse -- "plain digits, e.g. 0 or 2" --> some["some(n)"]
  parse -- "anything else" --> err["ApiMaxRetriesError, exit 1, 0 requests"]

  none --> defaults["client retries 5 times, deploy keeps its own loops"]

  some --> clients["Management API clients: retry.maxRetries = n"]
  clients --> platform["platform api: projects, secrets, link, ..."]
  clients --> login["login profile lookup"]
  clients --> services["services version lookup"]

  some --> deploy["functions deploy: apiMaxRetries"]
  deploy --> single["command loops capped, client retries off"]
  single --> dup["duplicated create still becomes one update"]
```

## why?

the management api client retries retryable failures up to 5 times with
no way to change that,
so eg: a failing `projects list` sends 6 requests, automation that has
to stop on the first failure had no supported way to send each request
once....

## ref

- closes: #6958
This bumps realtime from v2.151.4-r0 to v2.151.5-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.151.5-r0

Planned after supabase/slim-services published v2.151.5-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@supabase-cli-releaser supabase-cli-releaser Bot added the do not merge Approve to apply; do not merge. label Nov 3, 2026
@supabase-cli-releaser
supabase-cli-releaser Bot requested review from a team and supabase-oss as code owners November 3, 2026 02:15
supabase-cli-releaser Bot and others added 5 commits November 3, 2026 02:41
This bumps realtime from v2.151.5-r0 to v2.151.6-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.151.6-r0

Planned after supabase/slim-services published v2.151.6-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps postgres from 17.11.0.017-r0 to 17.11.0.018-r0.


https://github.com/supabase/slim-services/releases/tag/postgres-17.11.0.018-r0

Planned after supabase/slim-services published 17.11.0.018-orioledb-r0.
This branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This adds postgres 17.11.0.018-orioledb-r0 as a new release line.


https://github.com/supabase/slim-services/releases/tag/postgres-17.11.0.018-orioledb-r0

Planned after supabase/slim-services published 17.11.0.018-orioledb-r0.
This branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps postgres from 15.19.0.017-r0 to 15.19.0.018-r0.


https://github.com/supabase/slim-services/releases/tag/postgres-15.19.0.018-r0

Planned after supabase/slim-services published 17.11.0.018-orioledb-r0.
This branch is rewritten from develop whenever a newer relevant release
arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## Summary

Adds `supabase inspect db toast-sizes` — a new `inspect db` subcommand
that lists user tables with TOAST storage, ordered by TOAST size
(largest first).

## What changed

- `apps/cli/src/commands/inspect/db/toast-sizes/` — 3-file subcommand
(query, handler, command)
- `apps/cli/docs/supabase/inspect/db-toast-sizes.md` — docs overlay with
description and sample output
- `apps/cli/src/commands/inspect/db/db.command.ts` — registers the new
subcommand
- `apps/cli/src/commands/inspect/db/SIDE_EFFECTS.md` — updates active
count (13 → 14) and query table
- `apps/cli/src/commands/inspect/db/inspect-specs.integration.test.ts` —
adds a test case for `toastSizesSpec`

## Why it matters

TOAST (The Oversized-Attribute Storage Technique) is PostgreSQL's
overflow storage for large values in `TEXT`, `JSONB`, and `bytea`
columns. Autovacuum runs on TOAST tables **independently** from the main
heap, so dead TOAST chunks accumulate silently. A high TOAST dead-tuple
ratio increases I/O and inflates effective database size — but it
doesn't appear in the existing `bloat` or `vacuum-stats` commands, which
only cover the main heap.

This command surfaces:
- Heap vs. TOAST size split per table
- Live/dead TOAST chunk counts and dead-chunk percentage
- Last autovacuum/vacuum timestamps on the TOAST table

It's a common source of invisible bloat, especially in tables with large
JSONB columns.

## Testing

- New integration test case in `inspect-specs.integration.test.ts`
(count updated 13 → 14)
- Query filters out internal Supabase schemas via the shared `$1`
LIKE-escape parameter (consistent with `bloat`, `vacuum-stats`,
`index-stats`, `table-stats`, `db-stats`)
- Docs overlay at `apps/cli/docs/supabase/inspect/db-toast-sizes.md`
follows the same format as existing overlays

## Docs

A follow-up PR to `supabase/supabase` will add this command to the
[Inspect guide](https://supabase.com/docs/guides/observability/inspect)
under the **Disk Storage Analysis** section after this merges.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: avallete <andrew.valleteau@supabase.io>
## TL;DR

Adds `supabase inspect db collation-drift`, a read-only check for btree
indexes whose collation version no longer matches the version the OS now
provides. It lists the affected indexes and prints the remediation
workflow (amcheck → `REINDEX INDEX CONCURRENTLY` → `REFRESH VERSION`)
with the real object names. Supersedes
#6666 by @divyasharma95, whose
commits are kept as-is; this branch adds the port to the current inspect
runner and the review fixes.

## Why

After a glibc or ICU upgrade, btree indexes on text columns can be
mis-ordered with no error: queries may miss rows, sort incorrectly, or
let duplicates past a unique constraint. Postgres only warns about a
version mismatch; it does not say which indexes are affected or in which
order to fix them, and refreshing the recorded version before rebuilding
hides the problem.

## What changed

- New `inspect db collation-drift` command, sharing target selection,
permissions and connection resolution with the other `inspect db`
commands.
- Detects drift for the database default collation (PG15+) and for named
ICU and libc collations; on PG14 and earlier only named collations are
checked.
- Lists each affected index once, constraint-backing indexes first, and
skips partitioned parent indexes in favour of their partitions.
- Text output is a structured report: header, warning, table, and three
ordered remediation steps. `--output-format json` emits `{ rows, report
}`, keeping the `rows` shape of the other inspect commands.
- Introduces a small `Report` document model
(`apps/cli/src/output/report.types.ts`) and its text renderer, used only
by this command for now.

Known limitation: expression indexes (for example `lower(name)`) are not
detected; the remediation text tells users to rebuild them before
refreshing.

## Example output

```text
  Database          : postgres
  Affected indexes  : 1
  Keys / unique     : 1 (a wrong sort order here can admit duplicate rows)
  Default collation : 0.1 (recorded)  →  2.41 (current)

   ✗ | public.k_pkey | public.k | e | default | 0.1 | 2.41 | PRIMARY KEY | 8192 bytes

  1. Diagnose the listed indexes (optional)
  2. Rebuild every listed index
  3. Record the new collation version — only after every rebuild has finished
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Divya Sharma <divya.sharma@supabase.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
});
const resolvedSecrets = yield* resolveConfigSubtree(
resolvedConfig,
validatedConfig.edge_runtime.secrets ?? {},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Severity: MEDIUM

Project-controlled edge_runtime.secrets can now resolve arbitrary shell env() references: setting LEAK = "env(SUPABASE_ACCESS_TOKEN)" injects the token into the shared Functions environment. The later filter checks the variable name, not its value, so an invoked function can read LEAK and send the CLI credential off-host.
Helpful? Add 👍 / 👎

💡 Fix Suggestion

Suggestion: Stop edge_runtime.secrets from resolving env() references to the CLI's own credentials. Resolve these secrets with an allowlist or denylist. Reject or leave unresolved any env(NAME) reference where NAME starts with SUPABASE_ or is a known CLI credential such as SUPABASE_ACCESS_TOKEN. Do this inside or just before resolveConfigSubtree for the edge_runtime.secrets subtree, and return a StackConfigError when a reference is blocked. Also check the resolved secret values against the sensitive host values. The current !name.startsWith("SUPABASE_") filter only checks the secret's key, so it can't catch this case. Alternatively, resolve env() for secrets only from the project's dotenv files and not from the host shell environment.

avallete and others added 18 commits November 4, 2026 11:20
## TL;DR

Bumps `effect` and `@effect/*` from 4.0.2 to 4.1.2 with no user-visible
CLI change. Where effect 4.1 changes CLI output or parsing, a pnpm patch
keeps the 4.0 behaviour until the next major.

## Why

effect 4.1 brings `effect/cli` APIs we need for generating reference
docs from code. The upgrade also changes CLI behaviour that we can't
ship in a minor.

## What changed

- `effect`, `@effect/platform-*`, `@effect/sql-pg` and `@effect/vitest`
are now on 4.1.2.
- Code moves from the removed root `Crypto` module to `effect/crypto`
(`Digest`, `SecureRandom`). Error handling that can no longer fire is
removed.
- `patches/effect@4.1.2.patch` keeps 4.0 behaviour in these places:
  - a repeated single-value flag uses its first value
  - `--completions` accepts `bash|zsh|fish|sh`
  - an invalid value for a global flag doesn't also print the full help
- help keeps its 4.0 shape: no "INHERITED FLAGS" section and no new JSON
keys
  - the bash and zsh completion scripts stay the same
- `patches/@effect__platform-node-shared@4.1.2.patch` replaces `export *
from "ws"` with named re-exports. Without it, the `bun build --compile`
binary crashes at startup (oven-sh/bun#18008). The old stdin EPIPE patch
is dropped because effect 4.1 now has the same fix.
- Two runtime fixes that keep effect 4.0 stream behaviour:
- `effect` `Channel.restoreUpstreamFailure` unwraps upstream failures
outside the interruptible region. Without this, a stream failure racing
an interrupt leaks as a defect, which shows up as `Unhandled TCP
connection failure` in the stack proxy.
- `@effect/platform-node-shared` `NodeSink` treats
`ERR_STREAM_PREMATURE_CLOSE` as completion, as 4.0 did (4.0 had no
`finished()` check). Without this, writing to the stdin of a child
process that has already exited fails with `Premature close`.
- `ws@8.22.1` is exempted from the release-age gate because it is the
exact `ws` version `@effect/platform-node-shared@4.1.2` depends on.
- `@effect/vitest` patch rebased.
- `packages/config`: decoding and the published schemas are
byte-identical. Record value defaults go through a helper, and the new
integer bounds and nested-union output are normalised away.
- Changes accepted as-is: with `NO_COLOR` set, `--wizard` now prints no
ANSI colour. Two lexer edge cases (`--=x` and `-ab=v`) now give
different error text, with the same exit code.

Part of CLI-2919. CLI-2922 tracks aligning with effect 4.1 behaviour in
the next major.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## TL;DR

fixes Studio on the stack missing the local S3 keys, so creating a
vector bucket in Studio installs its wrapper like on the legacy backend

## ref:

- extends: #7483
This bumps storage from v1.89.6-r0 to v1.89.7-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.89.7-r0

Planned after supabase/slim-services published v1.89.7-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps storage from v1.89.7-r0 to v1.89.9-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.89.9-r0

Planned after supabase/slim-services published v1.89.8-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
## TL;DR

makes a migration that fails with `SQLSTATE 25P01` say how to fix the
file

## whats hurting?

`supabase db reset`, `db push`, `migration up` and `db diff` run each
migration file as one batch, and the CLI adds no `BEGIN`/`COMMIT` around
it

so a file with `LOCK TABLE` fails with `LOCK TABLE can only be used in
transaction blocks (SQLSTATE 25P01)` and the error gives no hint on what
to change

`db reset` stops at that file, so later migrations and the seed never
run

## now fixed by?

any 25P01 failure (`LOCK TABLE`, `DECLARE CURSOR`, `SAVEPOINT`) now
prints this hint under the postgres error

```
Hint: This statement must run inside an explicit BEGIN; ... COMMIT; block;
      the CLI adds none. Review any existing transaction boundaries.
      Move each non-transactional statement (e.g. VACUUM) to its own file.
```

how migrations run is unchanged, so the file still needs that edit
before it applies

<details><summary>visual rep</summary>

```mermaid
flowchart TD
  A["migration file with LOCK TABLE"]
  A -. before .-> B["25P01 with no hint"]
  B -.-> C["db reset stops, later migrations and seed skipped"]
  A -- now --> D["25P01 with the BEGIN/COMMIT hint"]
  D --> E["file wrapped in one BEGIN/COMMIT"]
  E --> F["db reset applies it, then the rest and the seed"]
  classDef t fill:transparent
  class A,B,C,D,E,F t
```

</details>

## ref:

- closes: #6347
## TL;DR

The comment on the `@effect/platform-node-shared` NodeWS patch now links
the pending Bun fix, so we know when the patch can be dropped. No
behaviour change.

## What changed

- `patches/@effect__platform-node-shared@4.1.2.patch` now also links
oven-sh/bun#46903, the open fix for oven-sh/bun#18008. Once Bun ships
that fix, the named re-export workaround can be removed.
- `pnpm-lock.yaml` updates the patch hash.

Neither the CLI nor `packages/stack` opens a websocket through `NodeWS`
at runtime; only the stack whole-stack test helpers do. So in the
compiled binary, the patch only needs `NodeWS` to load. Proxied
WebSocket upgrades go through raw `node:http` and are unaffected.

Follow-up to #7473 (CLI-2919).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This bumps realtime from v2.153.0-r0 to v2.153.1-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.153.1-r0

Planned after supabase/slim-services published v2.153.1-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…I-2252) (#7491)

`sso list` on a project whose auth service is down could sit on the
spinner for minutes: each attempt waited up to 60s and was retried five
times.

- `sso list` and `sso show` cap each attempt at 10s.
- When an SSO call fails with a transport error or 5xx, the CLI looks up
the project and warns if its status is not `ACTIVE_HEALTHY` (also on
`sso remove`). 4xx responses keep their existing SSO-specific errors.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… (#7498)

## TL;DR

fixes `db start --from-backup` on windows by passing the host path into
the backup bind as is,
 like all the other binds do currently...

## ref

- closes: #7493
- closes: #3468
This bumps realtime from v2.153.1-r0 to v2.153.2-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.153.2-r0

Planned after supabase/slim-services published v2.153.2-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: kanad <git@kanad.dev>
This bumps storage from v1.89.9-r0 to v1.89.12-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.89.12-r0

Planned after supabase/slim-services published v1.89.12-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps realtime from v2.153.2-r0 to v2.153.3-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.153.3-r0

Planned after supabase/slim-services published v2.153.3-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This bumps edge-runtime from v1.77.9-r0 to v1.78.0-r0.


https://github.com/supabase/slim-services/releases/tag/edge-runtime-v1.78.0-r0

Planned after supabase/slim-services published v1.78.0-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Julien Goux <hi@jgoux.dev>
…) (#7499)

## TL;DR

fixes the stack's Functions env so `supabase start` and `supabase
functions serve` give functions the same env as the legacy backend

## whats missing?

stack `functions serve` ignored each function's own
`supabase/functions/<slug>/.env`
the stack let `[edge_runtime.secrets]` win over
`supabase/functions/.env`, while legacy lets the file win

on a running stack `--env-file` kept the `functions/.env` values, and
`.env` edits only applied after a restart
multiline values like PEM keys were rejected

`--debug` printed less than legacy and the serve banner showed the
internal port
a stack where only Realtime serves the API failed with `Shared API port
differs from existing claim`

## fixed now by:

legacy and the stack now share one env resolver, and legacy `start` and
`functions serve` output stays exactly the same

stack `functions serve` reads each function's `.env`, re-reads env files
on every run and restores the saved config on exit
multiline values travel in the Functions config on native and docker

Realtime counts as an API source, and the runtime now gets the API port
and debug mode

## ref:

- missed in: #6684
- extends: #7481
… log stream failures (#7505)

## TL;DR
Docker 27 and later report an unreachable daemon as `failed to connect
to the docker API at …`, which the CLI's daemon-down checks did not
recognise, and the container-state check also missed the Windows `error
during connect` form. Both now count as "Docker is not running".
Separately, `functions serve` log stream failures with a reachable
Docker were all one unclassified `DockerLogsStreamError`. They now get a
fingerprint for each container outcome.

## What changed
- `isDockerDaemonUnreachable` matches the Docker 27+ wording.
- `isDockerDaemonDownMessage` matches the Docker 27+ wording, `error
during connect`, `is the docker daemon running` and the socket
permission-denied form, in addition to its existing rule.
- Commands and helpers that use these checks: Docker image resolution
and pre-pull, local database container lifecycle and running check, `gen
types`, the pgdelta seam, and `functions serve`.
- `DockerLogsStreamError` is fingerprinted from the follow-up container
inspect:
  - the inspect failed: `engine_command_inspect`
- exit 137 without an OOM flag: `container_killed`, as
`EdgeRuntimeContainerCrashedError` already does
  - exit 0 or a termination signal: `runtime_stopped`
  - any other non-zero exit: a runtime crash
- `externalTerminationExitCodes` moves to `serve.errors.ts`, so the
error and `serve.ts` share it.

## Behaviour change
When Docker prints one of these messages, the affected commands show the
Docker suggestion instead of the generic `--debug` hint, and report the
failure as `docker_not_running`. Container crashes during `functions
serve` log streaming now count as internal bugs instead of unknown
failures. Messages, exit codes and JSON `error.code` are unchanged.

## Linked issue
None

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Aligns the local stack gateway's CORS responses with the hosted platform
and adds a live parity test that keeps them aligned.


## Gateway changes (`packages/stack/src/HttpProxy.ts`)

For routes where the gateway owns CORS (everything except
`/functions/v1`):

- Preflights return `200` (was `204`), list
`GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS,TRACE,CONNECT`, and echo
`Access-Control-Request-Headers`, defaulting to
`accept-profile,apikey,authorization,x-client-info`.
- Proxied responses keep the upstream's CORS headers and set
`Access-Control-Allow-Origin` to the request origin; the gateway no
longer adds allow-methods/allow-headers to them.
- Responses the gateway generates itself (404, 502) carry `*` and the
methods list.

## Live parity test

`start.gateway-cors.live.test.ts` deploys an origin-restricted function
(and a `verify_jwt = true` copy) to the live suite's project, serves the
same functions from `stack start --runtime docker`, sends the same 10
probes to both, and asserts the stack's results equal staging's. Staging
is the oracle; no expected headers are hard-coded. It runs in the
existing live job.

`GET /rest/v1/` is not probed: with a publishable key the platform
answers 401 there and the stack 200, which is an auth difference, not a
gateway CORS one.

## Gateway parity matrix

Same 10 probes against a staging project, this branch's local stack
(`stack start --runtime docker`), and self-hosted Docker with
supabase/supabase#52709 and supabase/supabase#52710 applied. Cells read
status / allow-origin / allow-credentials / allow-methods /
allow-headers / expose-headers; "match" means identical to staging.
"methods list" is
`GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS,TRACE,CONNECT`. Self-hosted row
7 uses `FUNCTIONS_VERIFY_JWT=true`, the other rows `false`.

| Probe | Staging (oracle) | Dev stack (this PR) | Self-hosted
(52709+52710) |
|---|---|---|---|
| OPTIONS function, blocked origin | `403` / – / `true` / – / – / – |
match | match |
| OPTIONS function, allowed origin | `204` / `app origin` / `true` / – /
– / – | match | match |
| POST function, blocked origin | `200` / – / `true` / – / – / – | match
| match |
| POST function, allowed origin | `200` / `app origin` / `true` / – / –
/ – | match | match |
| POST missing function | `404` / `*` / – / – / `authorization,
x-client-info, apikey` / `sb-error-code` | match | match |
| OPTIONS missing function | `404` / `*` / – / – / `authorization,
x-client-info, apikey` / `sb-error-code` | match | match |
| POST verify_jwt function, invalid Bearer | `401` / `*` / – / – /
`authorization, x-client-info, apikey` / `sb-error-code` | match | match
|
| OPTIONS /rest/v1/, foreign origin | `200` / `*` / – / `methods list` /
`accept-profile,apikey,authorization,x-client-info` / – | match | `200`
/ `request origin` / – /
`GET,POST,PUT,PATCH,DELETE,OPTIONS,HEAD,CONNECT,TRACE` / (empty) / `*` |
| OPTIONS /rest/v1/ with request headers, foreign origin | `200` / `*` /
– / `methods list` / `authorization, x-custom-header` / – | match |
`200` / `request origin` / – /
`GET,POST,PUT,PATCH,DELETE,OPTIONS,HEAD,CONNECT,TRACE` / `authorization,
x-custom-header` / `*` |
| GET missing table, foreign origin | `404` / `request origin` / – / – /
– / `PostgREST list` | match | `404` / `request origin` / – / – / – /
`*` |

The local stack matches staging on every probe. Self-hosted matches on
all function probes; its REST CORS differs from staging and is outside
this PR.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
)

## TL;DR

Fixes an e2e port race and adds named per-phase deadlines to a test
whose stall cause is still unknown. The `sso list` flake originally in
this PR is already fixed on `develop` by #7502.

- **`status` e2e › reports a running local stack…** failed with Kong's
host port `address already in use`. The e2e helper picked ports by
binding port 0 and releasing it, so they came from the kernel's
ephemeral range, where an outbound connection on the runner could take
one before Docker published it. Ports now come from 1024–9999, below
both the stack's own allocation ranges (10000 and up, see
`packages/stack/src/Ports.ts`) and the OS ephemeral ranges, so neither a
concurrent stack-mode e2e nor an outbound connection can claim a probed
port. Each port is probed on `0.0.0.0`, as Docker binds it, and on
`127.0.0.1`, because macOS lets a wildcard bind succeed over a
loopback-only listener. Ports stay partitioned per e2e worker.
- **`DockerDatabaseStorage` › keeps the prior marker decodable when a
real kill lands…** hit the 20s test timeout and the failure didn't say
which step hung. Each remaining phase (helper image, `prepare`,
PG_VERSION seed, killed writer exit and pipe close, `markInitialized`
retry, both cleanups) now fails with a `PhaseStallError` naming the
phase, well before the test timeout. This is diagnostic-only; the next
failure will name the phase to fix.

## ref

spotted in:
- status e2e:
https://github.com/supabase/cli/actions/runs/41813449030/job/126518169570
- DockerDatabaseStorage:
https://github.com/supabase/cli/actions/runs/41820563616/job/126542347726

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Julien Goux <hi@jgoux.dev>
…LI-2860, CLI-2861) (#7488)

## Summary

The CLI now reads and writes `supabase/config.jsonc`, and treats
`config.json` the same way, so comments and trailing commas work and
survive every write the CLI makes to the config.

Reading:

- The loader looks for `config.json`, `config.jsonc` and `config.toml`
in `supabase/`. `config.jsonc` reports `format: "json"`, so everything
that already handles a JSON config treats it the same way
- Both JSON files go through `jsonc-parser`. A syntax error now names
its position, e.g. `Comma expected (line 4, column 3)`, instead of the
runtime's `JSON.parse` message
- The CLI warns once per command when a JSON config shadows
`config.toml`: `Ignoring supabase/config.toml because
supabase/config.json takes precedence. Delete the file you don't use.`
- The two comment strippers the CLI had (VS Code settings in `init`,
Deno import maps in `functions deploy`) use the same parser now, and the
experimental-feature reader and the upgrade notice's project walk-up
know about `config.jsonc`

Writing:

- `config pull` edits a JSON config in place through `jsonc-parser`'s
`modify` instead of re-serialising the whole file, so comments, trailing
commas and untouched values stay as they are. A new key goes after the
previous property's whole line, so a trailing comment stays with its own
key. ADR 0023 has an addendum for the new JSON strategy
- `saveCliConfig` applies the same minimal edits when it saves over an
existing `config.json`/`config.jsonc`, and removes a dropped key by its
whole line. Removing the last key of an object also drops the comma
before it, so a `config.json` stays strict JSON for older CLIs. If the
edited text doesn't re-parse to exactly the saved config, it falls back
to writing the regenerated file. A TOML save keeps the file's `#:schema`
line
- `saveCliConfig` writes back to `config.jsonc` when that's the
project's JSON file, and still removes the other config files after the
write
- `compute new` (experimental) records the new compute in a JSON config
through the same editor, instead of refusing
- `functions new` and the declarative `db pull` write their
`functions.<slug>` and `db.migrations.schema_paths` entries into a JSON
config through the same editor. Before, both appended TOML to a new
`config.toml` that the JSON file shadowed, so the setting never applied
- `init` treats an existing `config.json`, `config.jsonc` or
`config.toml` as an existing config and names that file when it refuses.
`init --force` and a blank `bootstrap` remove
`config.json`/`config.jsonc` when they write the fresh `config.toml`, so
the new template is the file that gets read

Messages:

- Errors, hints and suggestions that named `supabase/config.toml` or
gave TOML syntax now name the project's own config file and write the
key in its syntax. A TOML project still sees `[db] major_version = 17`,
and a JSON project sees `` `db.major_version` to `17` in
supabase/config.jsonc ``. Where the command has no config loaded, the
text says "your config file" or lists all three file names
- Command help says "the project config file" and uses dotted keys such
as `db.seed.sql_paths`
- `db-config.toml-read.ts` is renamed to `db-config.read.ts`, since it
reads every format

`jsonc-parser` is a new runtime dependency of `@supabase/config` (MIT,
no dependencies of its own). Its `parse()` turns a `__proto__` key into
the object's prototype, so `parseJsonc` builds values through its
`visit` API with own-property assignment instead.

## Behaviour changes for existing projects

- A `config.jsonc` next to `config.toml` now takes over from it. Before,
`config.jsonc` was never read. The new warning names `config.toml` as
ignored, so the switch shouldn't go unnoticed
- `config.json` and `config.jsonc` in the same `supabase/` directory is
now an error: `Found both supabase/config.json and
supabase/config.jsonc. Keep one and delete the other.` Before,
`config.jsonc` was ignored
- Projects that already had `config.json` next to `config.toml` now get
the warning above. `config.json` already won there, so which file is
read doesn't change
- `config pull` and `saveCliConfig` on a `config.json` now only change
what they write. Before, both rewrote the whole file
- The stack's advice to pin a service version now reads ``pin
`local.services.<service>.version` to "<version>" in your config file``
for every project, including TOML ones
- Errors for a missing project config name `supabase/config.toml,
config.json or config.jsonc` instead of only `config.toml`
- `init` in a project with only a `config.json`/`config.jsonc` now
reports the config as already there. Before, it wrote a `config.toml`
that the JSON file then shadowed. `init --force` in such a project now
removes the JSON file

## Linked issue

Closes CLI-2859
Closes CLI-2860
Closes CLI-2861

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Coly010 and others added 9 commits November 5, 2026 15:19
#7510)

## TL;DR
Two `functions deploy` failures were reported to telemetry as internal
bugs even though both are typed failures with a known cause. A
multi-function API deploy now fails with `FunctionsDeployFailedError`,
classified by the failure it wraps. A malformed `deno.json` or import
map now counts as invalid config.

## What changed
- `deployViaApi` collects each function's upload failure, plus the bulk
update failure, into a `FunctionsDeployFailedError` instead of a native
`AggregateError`.
- It extends `AggregateError`, so `errors`, the joined message and
`instanceof AggregateError` are unchanged.
- Its classification comes from its most severe cause, ranked internal
bug, then unclassified, then external service, then user-actionable, so
a user error never masks a CLI or upstream failure. For example, a
deploy whose uploads all fail with 401 becomes
`error:FunctionsDeployFailedError:auth` (`user_actionable`). With no
causes it falls back to `unknown`, not `internal_bug`.
- `FunctionImportMapSyntaxError` gets the `invalidConfig` classification
and its own fingerprint, `error:FunctionImportMapSyntaxError`. It still
reports `name: "SyntaxError"`.

## Behaviour change
Telemetry only. These failures stop counting as internal bugs and are
bucketed by their real cause. Messages, exit codes and JSON `error.code`
(`UnknownError`) are unchanged.

## Linked issue
None (Linear CLI-2910)
This PR was automatically created to sync the generated `@supabase/api`
package with the latest Management API OpenAPI document.

Changes were detected in the upstream OpenAPI documents exposed by
`https://api.supabase.com/api/v1-json` and
`https://api.supabase.com/api/v2-json`.

---------

Co-authored-by: jgoux <1443499+jgoux@users.noreply.github.com>
Co-authored-by: Julien Goux <hi@jgoux.dev>
This bumps realtime from v2.153.3-r0 to v2.153.4-r0.


https://github.com/supabase/slim-services/releases/tag/realtime-v2.153.4-r0

Planned after supabase/slim-services published v2.153.4-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…7515)

## Problem

PostgREST derives a view's relationships by following views in the
exposed schemas **and** in `db-extra-search-path`. `gen types` only
followed the generated schemas. When a view chain passed through an
extra search path schema, its relationships were lost, so the types
rejected embeds that work at runtime.

```sql
create schema api;
create schema extra;   -- [api].extra_search_path = ["extra"]
create table api.accounts (id int primary key);
create table private.invoices (
  id int primary key,
  account_id int not null references api.accounts (id)
);
create view extra.invoices as select * from private.invoices;
create view api.invoices   as select * from extra.invoices;
```

```mermaid
flowchart LR
  V["api.invoices<br/>(generated)"] --> E["extra.invoices<br/>(extra search path)"] --> T["private.invoices<br/>(FK → api.accounts)"]
```

`supabase gen types --schema api`, `Views.invoices.Relationships`:

```ts
// before
Relationships: []

// after
Relationships: [
  {
    foreignKeyName: "invoices_account_id_fkey"
    columns: ["account_id"]
    referencedRelation: "accounts"
    referencedColumns: ["id"]
  },
]
```

## Change

- Bump `@supabase/typegen` to 0.3.2 (postgrest-typegen 0.7.0,
supabase/sdk#329), which takes an `extraSearchPath` option.
- Every path that introspects the database passes
`[api].extra_search_path`: `--local`, `--remote=<db-url>`, and remote
projects or branches with a non-TypeScript `--lang`. For a project ref,
the matching `[remotes]` block applies, like it does for
`[api].schemas`.
- The setting is read even with `--schema`, because it describes the
target's PostgREST, not which schemas to generate. Without a
`config.toml`, the default `public, extensions` applies.
- Nothing in the extra search path schemas is generated unless
`--schema` or `[api].schemas` names it.
- Linked TypeScript generation runs on the Management API and is
unchanged.
## TL;DR

stops realtime, analytics and the pooler idling at over 2 GB each when
containerd's `LimitNOFILE=infinity` reaches the containers

## what's hurting the user(s)?

on Linux hosts where containerd runs with `LimitNOFILE=infinity` and a
high `fs.nr_open`, containers inherit an open file limit of about 1B
unless a ulimit is set

the erlang vm in those services sizes its port table from that limit

together they take about 6 GB more at idle on a 10 GB machine, and one
run there hit 24 OOM kills in about 6 minutes

## now fixed by?

the legacy backend and the experimental stack now set
`ERL_MAX_PORTS=65536`, the erlang default, on those containers without
touching their ulimit

on those hosts they now idle at about 170 to 550 MB each with no OOM
kills

```mermaid
flowchart LR
  subgraph before["before"]
    B1["nofile ~1B<br/>port table ~134M<br/>about 2.3 to 2.7 GB"]:::t
    B2["nofile ~1M<br/>port table ~1M<br/>about 180 to 630 MB"]:::t
    B3["nofile 1024<br/>port table 64K<br/>about 170 to 610 MB"]:::t
  end
  F{{"fix:<br/>ERL_MAX_PORTS=65536"}}:::t
  subgraph now["now"]
    A1["nofile ~1B<br/>port table 64K<br/>about 170 to 550 MB"]:::t
    A2["nofile ~1M<br/>port table 64K<br/>about 170 to 560 MB"]:::t
    A3["nofile 1024<br/>port table 64K<br/>about 170 to 550 MB"]:::t
  end
  B1 -.-> F
  B2 --> F
  B3 --> F
  F --> A1
  F --> A2
  F --> A3
  classDef t fill:transparent
  style before fill:transparent
  style now fill:transparent
```


## ref:

- closes: #7503
…7513)

## TL;DR

adds a consumer contract suite that runs the same `supabase-js` cases
against legacy, `stack/container` and `stack/native`

## whats introduced?

`tests/contract/cases.ts` holds cases for PostgREST, Auth with Mailpit
confirmation, Storage, Realtime and Functions with `verify_jwt`

each case runs unchanged against one real stack per setup in the normal
integration job using the keys and urls `start` reports

a new golden path in `start.e2e.test.ts` edits `auth.site_url` then
stops and starts and checks Auth picks up the new value

## why?

nothing proved the stack and legacy behave the same for a real client so
parity fixes had no shared place to add the case they make pass

## ref:

- closes: CLI-2574
)

The tokenless `gen types` e2e asserts the output never mentions the
offline profile's `http://127.0.0.1:1` API URL with a plain substring
check. The CLI prints `Target: local stack (127.0.0.1:<dbPort>)`, so
whenever the randomly allocated DB port starts with `1` (e.g. `1191`)
the assertion fails even though no remote call happened. Seen on
#7523.

The assertion now matches `127.0.0.1:1` only when no further port digit
follows.
## Summary

An unset `sslmode` (libpq's default, `prefer`) and an explicit
`sslmode=prefer` were TLS-only. That broke any remote Postgres or
Supavisor without TLS, such as a self-hosted stack, even though `psql`
connects to the same URL fine:

```
$ supabase db push --db-url "postgres://postgres:…@db.internal:5432/postgres"
failed to connect to postgres: failed to connect to `host=db.internal user=postgres database=postgres`: tls error (The server does not support SSL connections)
```

`prefer` and unset now follow libpq: try TLS first, then retry the same
host in plaintext.

| `sslmode` | before | after |
| --------------------------------- | --------------- | ---------------
|
| `disable` | plaintext | plaintext |
| `allow` | plaintext → TLS | plaintext → TLS |
| `prefer` / unset | TLS only | TLS → plaintext |
| `require`, `verify-ca`, `verify-full` | TLS only | TLS only |

Local targets (the running project stack) still connect in plaintext
without a TLS attempt.

### When the plaintext retry runs

The retry is limited to failures where the server could not do TLS.
Unreachable hosts and auth errors are not dialed again in plaintext.

```mermaid
flowchart TD
  T[TLS attempt] -->|connected| OK[use connection]
  T -->|"server answered N to SSLRequest,<br/>or the TLS handshake failed"| P[plaintext attempt, same host]
  T -->|"28000: pg_hba has no TLS entry<br/>(hostnossl only)"| P
  T -->|"28P01 / 3D000 / 42501<br/>(wrong password, missing database, …)"| F[fail]
  T -->|"anything else<br/>(unreachable, timeout, …)"| N[next host, if any]
  P -->|connected| OK
  P -->|"failed (not an auth error)"| N
```

For a 28000 rejection the retry matches libpq, which reconnects without
TLS when the server rejects a `prefer` TLS session. `require` and
stricter modes have no plaintext attempt, so they still fail on these
errors, with the existing `sslmode=disable` hint.

Fixes #4142
This bumps storage from v1.89.12-r0 to v1.89.13-r0.


https://github.com/supabase/slim-services/releases/tag/storage-v1.89.13-r0

Planned after supabase/slim-services published v1.89.13-r0. This branch
is rewritten from develop whenever a newer relevant release arrives.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Vaibhav <117663341+7ttp@users.noreply.github.com>
Co-authored-by: Julien Goux <hi@jgoux.dev>

This branch was successfully deployed

1 active (outdated) deployment
config-release — 3217fb4b Deployed Nov 5, 2026 by github-merge-queue[bot] via Publish #52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge Approve to apply; do not merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants