Commit Graph
38871 Commits
Author SHA1 Message Date
Danny White 28cd7ada35 fix(www): add local KB rewrite URL (#50452)
## What kind of change does this PR introduce?

Bug fix for the local www development environment.

## What is the current behaviour?

Running `pnpm dev:www` fails Next.js rewrite validation because
`NEXT_PUBLIC_KB_URL` is missing from the tracked public environment
defaults, producing an `undefined` destination for `/kb`.

## What is the new behaviour?

The tracked public environment defines the local KB URL, matching
`.env.local.example`, so the www rewrite configuration is valid in a
fresh checkout.

## To test

1. Run `pnpm dev:www`.
2. Open http://localhost:3000.
3. Confirm www starts without the `Invalid rewrites found` error for
`/kb`.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Configuration**
* Added a public URL setting for accessing the knowledge base service in
local development.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-16 06:21:26 +00:00
Danny White 7e9c483625 feat(ui): support bounded MultiSelector wrapping (#50439)
## What kind of change does this PR introduce?

UI component enhancement and Design System documentation update.

## What is the current behavior?

`MultiSelectorTrigger` can either limit the number of visible badges or
wrap every selected badge. Consumers cannot combine a numeric limit with
wrapping.

## What is the new behavior?

Adds `wrapBadges` so consumers can combine it with a numeric
`badgeLimit`. For example, `badgeLimit={3} wrapBadges` renders up to
three wrapped badges followed by the remaining `+n` count.

Existing `badgeLimit=\"wrap\"` behaviour remains supported.

## To test

1. Open the Design System Multi Select page.
2. Find the **Wrapped badge limit** example.
3. Confirm three selected fruit badges wrap within the trigger and the
remaining selections appear as `+2`.
4. Remove or add selections and confirm the visible badges and remaining
count update together.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a `wrapBadges` option to multi-select triggers, allowing
selected badges to wrap across multiple lines while retaining a numeric
badge limit.
- Numeric limits now show the specified badges and an overflow count for
additional selections.
  - Updated the example with controls for adjusting the badge limit.

- **Documentation**
  - Clarified multi-select badge limit and wrapping behavior.

- **Tests**
- Added coverage for badge limits, wrapping, visible selections, and
overflow counts.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-16 12:27:16 +10:00
Danny WhiteandJoshen Lim 229d04d65c feat(studio): give pipeline pages a standard detail header (#50253)
## What kind of change does this PR introduce?

Studio page-layout polish. This follows the merged destination-brand and
pipelines-list work in #50251 and #50252, and now targets `master`
directly.

## What is the current behaviour?

Pipeline child pages use a bespoke heading, provide limited destination
context, and shift substantially while pipeline and destination data
load.

## What is the new behaviour?

Adds standard breadcrumbs and page-header composition, destination
identity, the primary-database-to-destination path, lifecycle actions,
and child-route integration. Layout-matched loading placeholders keep
the header geometry stable until the resolved pipeline data is
available.

Removes the legacy Overview header and actions now owned by the shared
page shell, and restores standard content gutters around the existing
metrics and tables. Pipeline action errors are handled once by the
layout, avoiding duplicate notifications from the underlying mutations.
Pipeline actions are also temporarily disabled while a table reset is
running to prevent conflicting requests.

| Before | After |
| --- | --- |
| <img width="1131" height="801" alt="Replication Database ETL BigTable
ETL Team Supabase"
src="https://github.com/user-attachments/assets/3f0ebab0-7244-4aa1-81ac-8847f5f86d4a"
/> | <img width="1131" height="801" alt="Replication Database Agua
Basket Supabase"
src="https://github.com/user-attachments/assets/bcbbd150-2a3d-468d-9cb9-652a6de2040b"
/> |

## To test

1. Open a pipeline at
`/project/<ref>/database/replication/<pipeline-id>`.
2. Confirm there is one page header with one set of actions, followed by
a consistently padded Overview body.
3. Confirm the breadcrumbs, destination logo and name, status,
source-to-destination path, primary lifecycle action, and overflow
actions.
4. Start, stop, or restart the pipeline and confirm its status and
available actions update appropriately.
5. Reset a replicated table and confirm the pipeline lifecycle, update,
and overflow actions remain disabled until the reset finishes.
6. Throttle the initial pipeline and destination requests and confirm
the header retains its final geometry without showing fallback data.
7. Check the page at desktop and phone widths.

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-16 11:51:49 +10:00
Anthony LioandDanny White 38f448b01c fix(ui): tab component (#50183)
## What kind of change does this PR introduce?
bug fix on tab component + a small refactor

## What is the current behavior?

the active tab in an underline list gets border-b-2 while its siblings
get nothing, so it's 2px taller and its label sits higher than the rest
causing a smol layout shift within docs

## What is the new behavior?

- adds one absolute positioned bar that slides between tabs so nothing
moves
- favors track under an underline as an inset shadow vs a border

| state | preview |
| -------|------|
| before | <video
src="https://github.com/user-attachments/assets/b73820a6-2994-46d1-aa98-452681f0fef2"
/> |
| after | <video
src="https://github.com/user-attachments/assets/054cd67d-a50c-4aef-9340-a1e1d515047b"
/> |


## Test
1. visit [api
reference](https://docs-git-antlio-ui-components-tabs-supabase.vercel.app/docs/reference/javascript/installing?platform=npm&queryGroups=platform)
2. visit a [guide
](https://docs-git-antlio-ui-components-tabs-supabase.vercel.app/docs/guides/database/prisma)


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added an animated tab indicator that follows the active tab and adapts
to layout changes.
  - Added support for customizing tab indicator styling.
- Respects reduced-motion preferences by disabling indicator transitions
when appropriate.

- **Style**
  - Streamlined tab borders, spacing, and underlined-tab styling.
- Improved tab panel spacing and standardized tab behavior in
documentation examples.
- Centralized easing behavior for smoother overlays, dropdowns, slides,
and panels.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
2026-09-16 00:00:27 +03:00
Anthony Lio 6d08a747f1 fix(docs): guide reference perf enhancements (#50239)
## What kind of change does this PR introduce?

follow-up to #50235 to reduce reference page payloads and cold rendering
overhead

## What is the current behavior?

reference pages ship a large rsc payload inside the html _ most of it is
duplication rather than content along with shiki that writes ~30
character css variable name for every syntax token making the page heavy
in some cases

## What is the new behavior?

- moves repeated styles into shared css and uses compact, namespaced
token classes
- renders details icons inside the client trigger
- follows shiki’s guidance to [reuse one
highlighter](https://shiki.style/guide/best-performance#cache-the-highlighter-instance)
and [load languages on
demand](https://shiki.style/guide/best-performance#use-shorthands)

`page size`
page | before | after | change
-- | -- | -- | --
javascript | 10.61 mb | 8.28 mb | -21.9%
dart | 4.59 mb | 4.13 mb | -10.1%
python | 4.38 mb | 3.73 mb | -14.9%
swift | 2.87 mb | 2.56 mb | -10.9%
server | 1.59 mb | 1.35 mb | -15.2%
kotlin | 3.42 mb | 3.17 mb | -7.2%

`cold initialization`
language | before | after | reduction
-- | -- | -- | --
bash | 2,180 ms | 23 ms | 98.95%
javascript | 2,245 ms | 38 ms | 98.29%

## Additional context

measured on a local production build which uses the checked in generated
content _ production has larger sdk data, so absolute sizes there will
be higher

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added reusable expand/collapse controls for API reference details,
with updated icons, labels, and styling.
* Improved code block rendering with class-based syntax highlighting,
wrapped-code support, responsive layouts, and lazy language loading.

* **Style**
* Added theme-aware syntax-token colors, line-number styling, and
configurable code-block shadows.
  * Consolidated expandable reference panel and item styling.

* **Tests**
* Added coverage for syntax highlighting, code block rendering, language
support, token stability, and reference details.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 23:55:49 +03:00
Manuel Rubio e693f206f5 fix(self-hosted): remove expose of app.settings.jwt_secret (#45003) 2026-09-15 19:38:21 +02:00
Andrew ValleteauandClaude Fable 5.1 10eaab766f fix(studio): filter on every column when viewing a composite FK record (#50256)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Bug fix

## What is the current behavior?

In the Table Editor, the "View referencing record" arrow on a foreign
key cell builds its filter from the table's `relationships` list. That
list is one entry per source-by-target column combination, and the
formatter takes the first entry whose source column matches the clicked
cell, then filters the referenced table on that single target column.

For a composite foreign key this fails in two ways:

- The value from the clicked column can be applied to the wrong target
column (whichever target column happens to be listed first for that
source column).
- Only one of the key columns is ever filtered on, so the peek and the
"Open table" link return zero rows or too many rows.

This is distinct from #41068 / #41080, which fixed the cartesian
expansion in the shared `tables.ts` introspection query. The bug
reproduces with that fix in place because the mis-pairing happens in
Studio when building the filter. Reported by a customer via support.

### Reproduction

Run this in the SQL editor. The referenced column list `(org_id,
bucket_id)` is deliberately not in the referenced table's physical
column order, which is what exposes the bug.

```sql
create schema if not exists dcs;

-- bucket_id declared first, org_id second
create table dcs.org_metering_buckets (
  bucket_id bigint not null,
  org_id    bigint not null,
  primary key (org_id, bucket_id)
);

create table dcs.machine_storage_usage_buckets (
  org_id                 bigint not null,
  org_metering_bucket_id bigint not null,
  constraint machine_storage_usage_buckets_org_metering_bucket_fkey
    foreign key (org_id, org_metering_bucket_id)
    references dcs.org_metering_buckets (org_id, bucket_id)
);

insert into dcs.org_metering_buckets (bucket_id, org_id) values
  (901, 1), (902, 1), (903, 2);

insert into dcs.machine_storage_usage_buckets (org_id, org_metering_bucket_id) values
  (1, 901), (1, 902), (2, 903);
```

1. Open `dcs.machine_storage_usage_buckets` in the Table Editor (select
the `dcs` schema).
2. Hover the `org_id` cell on the row where `org_id = 2`.
3. Click the "View referencing record" arrow.
4. Click "Open table" in the popover.

**Before this PR:** the popover shows "No results were returned". "Open
table" opens `dcs.org_metering_buckets` with a single filter `bucket_id
= 2`, which matches nothing.

**After this PR:** the popover shows the one row `(bucket_id = 903,
org_id = 2)`. "Open table" opens `dcs.org_metering_buckets` with two
filters, `org_id = 2` and `bucket_id = 903`, and the URL carries two
`filter=` params. Clicking the arrow on the `org_metering_bucket_id`
cell of the same row produces the same result.

Extra checks worth doing while you are there:

- Set one of the two key columns to NULL on a row. The arrow should
disappear for both key cells on that row, since a row with a null key
column does not reference anything under MATCH SIMPLE.
- A single-column foreign key (any existing table) should behave exactly
as before.

## What is the new behavior?

- New `ForeignKeyFormatter.utils.ts` with two pure functions.
`findColumnForeignKeyConstraint` locates the constraint on the current
table that contains the clicked column. `getReferencingRecordFilters`
pairs each source column with the target column at the same ordinal
position and builds one equality filter per pair from the row's values,
keeping the existing bytea-to-hex handling per column. It returns no
filters when any key column is null.
- `ForeignKeyFormatter` now reads the foreign key constraints query,
which returns ordinally paired source and target column arrays, instead
of the `relationships` list. The grid already fetches that query for the
same schema, so it is served from the React Query cache.
- `ReferenceRecordPeek` takes a `filters` array instead of a single
column and value. Both the peek query and the "Open table" link use the
full set, and the link emits one URI-encoded `filter=` param per column.
- Unit tests cover the reproduction above, single-column keys, bytea
values, null and missing values, falsy-but-valid values such as `0`, and
malformed constraints.

## Additional context

The table-editor introspection SQL in
`packages/pg-meta/src/sql/studio/table-editor/table.ts` and
`tables-paginated.ts` still expands composite foreign keys as a
cartesian product. #41080 only fixed the shared `tables.ts` query. The
arrow no longer depends on that data, but it can still mislabel the
referenced column elsewhere in Studio, so that is left for a follow-up
rather than widening this change into pg-meta SQL.

Before:
<img width="836" height="504" alt="Screenshot 2026-09-14 at 11 22 49"
src="https://github.com/user-attachments/assets/4645d64f-9bcb-44b0-b5b1-ab11ba7436db"
/>

After:
<img width="873" height="570" alt="Screenshot 2026-09-14 at 11 23 14"
src="https://github.com/user-attachments/assets/f2c47121-fd75-4efe-a370-28015c1b674e"
/>



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

https://claude.ai/code/session_01SkH86UV1KD4Xs5k9vt43tW

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved foreign-key record previews to correctly identify referenced
records across schemas and tables.
* Added support for composite foreign keys, ensuring previews and “Open
table” links apply all required column filters.
* Improved handling of binary values and incomplete or null foreign-key
data.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 19:22:04 +02:00
Mandar Joshi 0a409db31c fix(self-hosted): proxy .well-known route for auth (#50306) 2026-09-15 19:01:59 +02:00
Siddharth Gaikwad 920459e9be fix(docker): ship volumes/storage so it is not created as root (#50299) 2026-09-15 18:50:00 +02:00
Ali Waseem 5b099ee03f chore: share Sentry browser-noise filters between studio and docs FE-4392 (#50407)
Studio and docs each kept their own Sentry `ignoreErrors` list, so
browser-extension and DOM-mutation noise that Studio already filtered
still reached Sentry from docs. Moved the app-agnostic filters (network,
extension DOM mutation, non-Error throws, cross-origin script errors)
into `packages/common/sentry.ts` and spread them into both client
configs, leaving app-specific entries local. Docs will stop reporting
extension-driven `insertBefore`/`removeChild` crashes, matching Studio's
existing behavior — `ignoreErrors` drops events before `beforeSend`
runs, so the error-boundary exemption no longer applies to them.

Fixes FE-4392

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Reduced non-actionable browser noise in error monitoring by filtering
known network, browser extension, DOM-manipulation, cross-origin, and
non-error failures.
- Applied consistent filtering across the documentation site and studio
error tracking.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 09:38:36 -06:00
Vaibhav 254da82c3a feat: surface role risks (#50410)
## TL;DR 

Bolds the consequences in the Owner and Administrator role descriptions,
and adds a confirmation step before an invite for either role is sent.


https://github.com/user-attachments/assets/c8fb53ae-66c3-4862-865e-f2ff9fb84a8e

## ref: 

- recurring in the community:
organizations losing access to their own projects after inviting someone
as owner

eg:
https://discord.com/channels/839993398554656828/1545087567706193970/1545102402871492759

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added a confirmation step when inviting members as Owners or
Administrators.
- Invitations are sent only after the elevated-role warning is
confirmed.
- Confirmation behavior is consistent for form submissions and
keyboard-triggered invitations.

- **Updates**
- Refined role permission descriptions, including clearer details about
elevated access and project deletion capabilities.
- Improved role descriptions shown during member invitations and role
selection.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 15:25:46 +00:00
Gildas Garcia 24f89f3967 MFA Recovery codes: allow users to regenerate their codes (#50336)
## What kind of change does this PR introduce?

Once users have recovery codes generated, allow them to regenerate the
codes.

This PR also automatically check the _I have copied the codes_ after
clicking the _Copy to clipboard button_.

> [!NOTE]
> The _Delete my recovery codes_ button only appear on local and staging
environments

## How to test

- On an account that already have recovery codes generated
- You should see an admonition showing the remaining codes available and
allowing you to regenerate the codes

## Screenshots

<img width="706" height="193" alt="image"
src="https://github.com/user-attachments/assets/001bfa87-74f5-4867-8564-09cb6f91adb6"
/>

<img width="425" height="277" alt="image"
src="https://github.com/user-attachments/assets/711b139c-f806-4da2-a240-fa7e7fd8acd0"
/>

<img width="548" height="353" alt="image"
src="https://github.com/user-attachments/assets/d6521a09-3a7f-4198-b162-9effc218fee6"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added a recovery-code modal with copy-to-clipboard support and
confirmation before closing.
- Added an option to regenerate MFA recovery codes with a confirmation
step.
  - Recovery-code controls now appear when existing codes are available.
- Added loading, success, error, and retry states for recovery-code
generation and regeneration.

- **Bug Fixes**
- Updated the recovery-code generation error message to more accurately
describe the failed action.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 16:38:41 +02:00
Katerina Skroumpelou 68acece226 docs: drop the retired withSupabase middleware option from the intro (#50409)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Docs fix, one sentence removed from the `@supabase/middleware` reference
intro.

## What is the current behavior?

The alpha admonition says the `middleware` option on `withSupabase` in
`@supabase/server` is also alpha. That option was removed in
`@supabase/server` 1.6.0, where `withSupabase` became a `pipeline`
entry, so the sentence describes something that no longer exists.

## What is the new behavior?

The admonition keeps the `@supabase/middleware` alpha wording and drops
the sentence about the removed option. Both hand-maintained copies of
the intro are updated and stay identical: the spec partial that renders
the reference site, and the `docs/ref` copy that feeds the markdown
build.

## Additional context

Same two-file pattern the `@supabase/server` reference uses for its
intro and installing partials.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Documentation**
- Updated middleware documentation to clarify that only the
`@supabase/middleware` package is in alpha.
- Removed the alpha-status notice for the `withSupabase` middleware
option in `@supabase/server`.
- Clarified that `@supabase/middleware` APIs may change between 0.x
releases.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 17:29:13 +03:00
86f38f97c8 docs: add troubleshooting entry for the Edge Function secrets limit (#50366)
## Summary
- No public doc previously covered what to do when a project hits the
100-secret cap for Edge Functions. Adds a troubleshooting entry
documenting the JSON-bundling workaround.
- Cross-links the new entry from the Secrets section of
`functions/limits.mdx`.

## Sourcing / context
- Internal Slack (Jul 2):
https://supabase.slack.com/archives/C02KMRX22NR/p1783003062600709?thread_ts=1783002978.740289&cid=C02KMRX22NR
— workaround first suggested (Kalleby).
- Internal Slack (Aug 19):
https://supabase.slack.com/archives/C0BMQHEU6N6/p1787139772204509?thread_ts=1787098919.509189&cid=C0BMQHEU6N6
— functions team reconfirms no override path exists; workaround
independently recommended again.
- The JSON-bundling pattern mirrors how Supabase's own default secrets
already work (`SUPABASE_PUBLISHABLE_KEYS` / `SUPABASE_SECRET_KEYS` in
`functions/secrets.mdx`), so this isn't a novel pattern for the
platform.
- Prompted by support ticket SU-473846.

## Test plan
- [x] `pnpm --filter docs lint:mdx` passes with no warnings on either
changed file
- [ ] New page renders correctly under `/docs/guides/troubleshooting`
- [ ] Link from `functions/limits.mdx` resolves

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Documentation**
- Added guidance for working around the 100-secret Edge Functions limit
by bundling related credentials into a single JSON secret.
- Documented JSON secret setup, parsing, replacement behavior, shell
quoting, environment files, and the 48 KiB per-secret size limit.
- Clarified that JSON bundling does not bypass the per-secret size
limit.
- Explained when to use Supabase Vault for row- or user-specific
secrets, including database round trips and potential latency.
- Linked the workaround guide from the Edge Functions limits
documentation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Miranda Limonczenko <miranda.limonczenko@supabase.io>
2026-09-15 10:13:46 -04:00
Joaquim Moreno Prusi b824acdfd2 feat(project-creation): support Kubernetes cluster override for internal project creation (#49956)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Feature, internal

## What is the current behavior?

When creating a project, the worker will use load balancing to decide
where to deploy a cluster.

## What is the new behavior?

An internal user can choose a specific cluster and even bypass the
CORDONED state by forcing deployment.


## Additional context

This PR adds kubernetesClusterId and kubernetesClusterForce to the
internal-only project creation form for K8S cloud providers, gated by
schema validation (provider-restricted; force requires an ID) and
cleared automatically on provider change. The override is a one-time
creation-time steer, not a persistent pin, and the UI copy reflects
that. Includes the matching
kubernetes_cluster_id/kubernetes_cluster_force request fields in the
generated platform API types.

<img width="1620" height="1352" alt="image"
src="https://github.com/user-attachments/assets/bd8965a1-cec8-4428-aac1-46d0bf3b89d3"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added Kubernetes cluster ID entry during project creation for
supported cloud providers.
  * Added an option to force deployment to a specified cluster.
* Clarified that eligible clusters must meet status and filesystem
requirements.

* **Bug Fixes**
* Prevented invalid or outdated Kubernetes settings from being submitted
when the provider or cluster selection changes.
  * Treated blank or whitespace-only cluster IDs as unset.
* Prevented force-deployment requests without a cluster ID or for
unsupported providers.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 13:46:49 +02:00
Alaister YoungandAlaister Young 3bac7165bd chore(studio): move the TanStack Start deploy onto Nitro (#50030)
Moves the Studio TanStack Start build off the hand-rolled Vercel setup
(an `api/server.js` function shim, rewrites in `vercel.ts`, a custom
`?dpl=` skew-protection Vite plugin, and `scripts/serve.js` for
self-hosted) and onto Nitro, which TanStack Start documents as its
deployment path. Documents are served from the static SPA shell on the
CDN; only `/api/*` and `/_serverFn/*` invoke the function.

**Removed:**
- `api/server.js`, `scripts/serve.js`, `scripts/smoke-server.mjs`
- The `skewProtectionDpl` Vite plugin, `renderBuiltUrl`, and the
`vite:preloadError` reload backstop in `router.tsx` (TanStack Router
already reloads once on a failed lazy import)
- Rewrites, `functions`, `outputDirectory`, and `cleanUrls` from
`vercel.ts` (redirects and headers stay)
- `magic-string` and `@jridgewell/remapping` devDependencies, the
`preview` script

**Added:**
- `nitro` plugin in `vite.config.ts`. Preset is auto-detected:
`.vercel/output` on Vercel, a self-contained node server in `.output`
everywhere else. `vercel.immutableStaticFiles` puts hashed chunks under
`/_vercel/immutable/` so tabs opened before a redeploy keep loading
their chunks; `functions.maxDuration: 300` carries over the old function
timeout
- `scripts/vercel-spa-routes.ts`: Nitro module that rewrites the
generated Build Output routes (documents -> `_shell.html`, allow-list ->
`__server`, missing chunk -> 404, base-path prefixes), with a unit test
- `server.ts`: TanStack Start server entry that initializes Sentry
before the route tree loads and wraps the handler with
`wrapFetchWithSentry`

**Changed:**
- `start:tanstack` runs `.output/server/index.mjs` directly with Node's
`--env-file-if-exists` for the `.env` cascade. Node doesn't expand
`$VAR` references, so `scripts/generateLocalEnv.js` now writes literal
values into `.env.test`
- Dockerfile's TanStack stage copies `.output` instead of running `pnpm
deploy`; the `server.js` shim loads `.env` and imports the Nitro server
- `NEXT_PUBLIC_BASE_PATH` (the platform's `/dashboard`) only sets the
router basepath; Vite's `base` stays at the root so chunks can use the
immutable store. The routes module emits prefixed rules for
`/dashboard/api/*` and `/dashboard/_serverFn/*` and rewrites `public/`
files requested under the prefix back to the root
- Self-hosted security headers come from a Nitro `routeRules` entry; on
Vercel they stay in `vercel.ts`
- `tslib` is inlined for the build only: Nitro's dev runner has no
interop for its CJS wrapper
- Monaco's worker chunks follow the client assets dir so they land in
the immutable store too

Verified on the `studio-staging` preview (`STUDIO_FRAMEWORK=tanstack` is
scoped to this branch there): documents come back as the static shell,
`/dashboard/api/*` hits the function, `public/` files resolve under the
prefix, a missing immutable chunk 404s. Across two deployments of this
branch, the older deployment's chunks still load from the immutable
store and requests carrying its `__vdpl` cookie are answered by that
deployment. Self-hosted path covered by the TanStack E2E job and the
Docker build job.

## To test

- On the `studio-staging` preview: `/dashboard/project/<ref>` should
show `content-disposition: inline; filename="_shell.html"` and a
single-region `x-vercel-id`; `/dashboard/api/get-utc-time` a two-region
id
- Sign in and click through a few pages, including one that opens Monaco
(SQL editor) so the worker chunks load
- After the next deploy, a tab left open on the previous one should
still navigate (lazy chunks) and call the API without errors
- Self-hosted: `STUDIO_FRAMEWORK=tanstack pnpm --filter studio build &&
pnpm --filter studio start`, then check `/api/platform/profile` and that
responses carry the security headers


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Production TanStack deployments now run on Nitro’s self-contained
server output.
* Vercel routing serves static pages first while directing API and
server-function requests appropriately.
* Server-function requests can include deployment identification for
consistent handling.
* Local environment generation now writes resolved configuration values.

* **Bug Fixes**
  * Improved handling of missing static assets and SPA fallback routing.
* Server-side error monitoring now captures request errors in the new
runtime.

* **Refactor**
* Replaced the legacy production server and smoke-test workflow with
Nitro-based startup.
  * Removed automatic reload handling for stale client assets.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-09-15 21:46:45 +10:00
Ivan Vasilov 0db2667819 chore: Bump vulnerable dependencies (#50008)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Chores**
  - Updated underlying web platform components to newer versions.
- Improved compatibility and maintenance across the documentation and
website experiences.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 13:16:57 +02:00
Jordi Enric fa7c223209 fix(studio): use Compute management endpoints FUNC-896 (#50393)
## Problem

Studio still called the legacy `/workers` Management API routes and used
the old `project_worker` response contract, so Compute instances could
not be listed or retrieved after the API rename. The production API type
check also detected drift in the v1 and platform declarations.

## Fix

- Regenerate the v1, v2, and platform API declarations from the deployed
schemas.
- Update Studio list and detail queries to `/compute`.
- Align typed fixtures with the Compute response schemas and
`project_compute_instance` resource type.
- Update platform response type references to the generated `_Output`
schema names.

## How to test

- Run `pnpm api:verify-types`.
- Run `pnpm --filter api-types test`.
- Run `pnpm --filter studio test data/compute/compute.utils.test.ts
"tests/pages/project/[ref]/compute/index.test.tsx"`.
- Run `pnpm --filter studio typecheck`.
- Run `pnpm --filter common typecheck`.
- Run `pnpm --filter studio lint:ratchet`.

Expected result: production API declarations are synchronized, and
Studio requests the `/compute` list and detail endpoints and renders
`project_compute_instance` responses successfully.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Updated API response handling across profiles, backups, notifications,
integrations, warehouses, access tokens, payments, and other Studio
workflows for more accurate serialized data.
* Compute instance pages and queries now use the compute-specific API
endpoints and response data.
* Improved feature-flag type handling when disabled feature data is
unavailable.

* **Tests**
* Updated automated coverage and fixtures to reflect current compute and
API response formats.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 12:50:56 +02:00
Artur Zakirov b86b5feabd docs(orioledb): Add Configuration section (#50329)
- Add "Configuration" section into the OrioleDB docs
- Update the information about supported indexes: OrioleDB now supports
  non-btree indexes via index bridging
2026-09-15 12:07:13 +02:00
Jordi Enric c228ca4f61 fix(studio): restore function deployment annotations FE-3921 (#50362)
## Problem

The Edge Function overview converted the numeric deployment timestamp to
a string before parsing it as a date. This produced an invalid date, so
the invocations chart omitted the deployment annotation.

## Fix

Preserve the numeric timestamp returned by the API and allow the
annotation helper to parse both numeric and string timestamps. Show
deployment details in an accessible tooltip when hovering or focusing
the rocket marker, and add regression coverage for numeric timestamps
and the existing invalid, missing, and out-of-range cases.

## How to test

- Run the focused EdgeFunctionOverview utility test suite.
- Open an Edge Function whose latest deployment is within the selected
chart interval.
- Hover or focus the rocket marker.
- Expected result: the invocations chart shows the dashed deployment
line and rocket marker, and the marker tooltip shows the deployment
time.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Invocation update annotations now display correctly when function
update times are provided as numbers.
  - Timestamps at the start of the Unix epoch are now supported.
- Annotations no longer appear when update times are invalid or chart
data is incomplete.

- **Accessibility**
- Deployment markers in invocation charts are now keyboard-focusable and
include accessible labels.
  - Deployment timestamps are available in a tooltip on hover or focus.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 12:04:15 +02:00
Joshen Lim 4b24548345 Fix sync between filter bar and filter controls in unified logs (#50383)
### Context

In unified logs, adding a filter to the filter bar (e.g filtering on log
type) doesn't sync with the filter controls in the left menu (although
it does the other way around). Example here filtering on log type to
equals to edge (API Gateway)
<img width="400" alt="image"
src="https://github.com/user-attachments/assets/080aba77-3366-4530-8443-3c8902aefd20"
/>

Both filter bar and filter controls share the same URL state with nuqs,
and it comes in 2 shapes:
- a bare `string[]` for = conditions
- a wrapped `{ operator, values }` object for other operators

The filter bar didn't follow this convention for the first one as it
always wrote the wrapped object which made the checkbox appear untickets
on the filter controls (which expects the first one) - this always
caused the filter to show up as `[object Object]` if you add a log type
filter via the filter bar first, then check the same log type filter in
the filter controls.

### Changes involved
Am opting to streamline the expected data shape and have both components
always expect the wrapped object shape so we don't have to deal with 2
different shapes (feels unnecessary)

### To test
- Verify that applying a log type filter (e.g postgres) in the filter
bar should reflect the checkbox for the same log type filter in the
filter controls on the left to be checked as well
- Unchecking the checkbox in the filter controls should thereafter
remove the filter in the filter bar too

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Improvements**
- Unified Logs filters now use a consistent operator-and-values format
across filtering controls.
- Checkbox filters preserve operators when selecting multiple values or
using **Only**.
- Mixed filter conditions are handled more consistently, with
unsupported values ignored.
- Non-text filter values are converted consistently for reliable
filtering.
- **Bug Fixes**
- Improved consistency when applying, displaying, and updating Unified
Logs column filters.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 17:45:42 +08:00
Jordi Enric 8984305b1e feat: sample non-crash sentry errors at one percent (#50339)
## Problem

Browser Sentry reporting sends ordinary application errors at full
volume even though full-page crashes are the highest-priority signal.

## Fix

Sample eligible browser errors without `globalErrorBoundary` at 1%
across Studio, www, and docs. Keep 100% of eligible errors tagged with
`globalErrorBoundary`, preserve consent and existing noise filters, and
record the applied rate in `codeSampleRate`.

## How to test

- Run `node node_modules/vitest/vitest.mjs run
../../packages/common/sentry.test.ts lib/sentry-capture.test.tsx` from
`apps/www`.
- Run `node node_modules/vitest/vitest.mjs run
lib/sentry-client-options.test.ts` from `apps/studio`.
- Expected result: tagged page crashes bypass sampling, ordinary errors
use the 1% cutoff, and Studio applies sampling once while preserving its
existing filters.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Improved error reporting reliability by ensuring page-crash errors are
captured without sampling.
- Non-crash application errors are now sampled at a low rate, with
sampling metadata retained for monitoring.
- Updated filtering behavior so relevant Studio errors continue to be
reported consistently, including errors previously affected by
client-side filtering.
- Preserved filtering for third-party-only errors that do not represent
application failures.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 11:43:24 +02:00
Gildas Garcia 63bedef77f MFA Recovery codes: allow users to download their recovery codes (#50267)
## What kind of change does this PR introduce?

After users have set up a new MFA (first or not), we must:

- check whether recovery codes have already been generated
- if there are none, generate recovery codes and display them, "forcing"
users to copy them
- if already generated, show them how many are still available

> [!NOTE]
> The _Delete my recovery codes_ button in last screenshot only appear
on local and staging environments

## How to test

- On an account that doesn't have recovery codes generated yet and has
an MFA added
- You should see an admonition suggesting to generate the codes

## Screenshots

<img width="729" height="306" alt="image"
src="https://github.com/user-attachments/assets/79ba3870-4ef8-4571-9fd6-36eed20c9c24"
/>

<img width="550" height="356" alt="image"
src="https://github.com/user-attachments/assets/1632611a-996a-470d-b6cd-a4693b0f4602"
/>

<img width="719" height="205" alt="image"
src="https://github.com/user-attachments/assets/73cef611-05cf-4fac-bbd2-243f9b28e48d"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added support for generating, copying, and confirming MFA recovery
codes.
- Added recovery-code status visibility, including remaining and
exhausted codes.
  - Added the ability to delete recovery codes with confirmation.
- Added clear loading, success, and error states for recovery-code
actions.
  - Recovery-code status refreshes after codes are generated or deleted.

- **Bug Fixes**
- Recovery-code notices now remain visible when all codes have been
used.
  - Recovery-code dialogs can now be closed after generation errors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 11:16:47 +02:00
Jordi Enric 24f8549e41 fix(studio): open edge function logs from chart clicks FE-3922 (#50364)
## Problem

Clicking an invocation bar on the Edge Function overview did not
preserve the selected chart segment, so the destination could not open a
focused investigation window.

## Fix

Forward the clicked bar timestamp and navigate to Logs or Invocations
with an encoded, focused time range. Share the existing chart range
calculation and add real Recharts interaction coverage.

## How to test

- Open an Edge Function Overview page with invocation data.
- Click a populated bar in the Total Invocations chart.
- Expected result: Logs or Invocations opens with its and ite query
parameters centered on the clicked bar.
- Repeat with unified logs enabled and disabled to verify both
destinations.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Clicking a bar in the Edge Function invocations chart now opens the
relevant logs or invocations view.
- The destination is focused on a time window surrounding the selected
invocation, making investigation faster.
- Chart bars now provide a pointer cursor to indicate they are
interactive.

- **Bug Fixes**
- Chart clicks without valid invocation data no longer trigger incorrect
navigation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 11:06:37 +02:00
Ali Waseem 56820eb048 fix(studio): use configured gp3 max-throughput ceiling (#50355)
`calculateMaxThroughput` still hard-capped at 1000 MB/s while
`DISK_LIMITS.gp3.maxThroughput` moved to 2000, so large gp3 disks were
rejected with a misleading "Need at least N IOPS to support X MB/s"
error even when IOPS and compute were already sufficient. Now reads the
configured ceiling, mirroring the IOPS fix in #50269 that missed this
sibling.

Fixes FE-4385

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- GP3 storage configurations can now support throughput scaling up to
2,000 MB/s when sufficient compute capacity is available.
- Larger GP3 configurations, including up to 4,096 GB with 80,000 IOPS
and 2,000 MB/s throughput, are now recognized as valid when capacity
requirements are met.

- **Bug Fixes**
- Corrected the maximum GP3 throughput calculation to honor the
supported service limit.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 17:00:10 +08:00
Jake Ng 608c3a0813 chore(docs): add Jake Ng to humans.txt (#50378)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Add Jake Ng to humans.txt

## What is the current behavior?

Jake Ng is not in humans.txt

## What is the new behavior?

Jake Ng has joined Supabase

## Additional context

Done as part of the onboarding tasks.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Documentation**
* Added Jake Ng to the team member list in the public contributor
information.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 10:38:28 +02:00
Joshen Lim ad5202d53d Joshenlim/fe 4378 update editorpanel save cta when explorer is enabled (#50324)
## Context

Swaps out the "Save as snippet" CTA in the `EditorPanel` to the "Save to
notebook" dropdown CTA if explorer is enabled
<img width="488" height="147" alt="image"
src="https://github.com/user-attachments/assets/915017a1-c416-4904-8146-b0695244d2bd"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added a save-query dropdown in Explorer for creating a new notebook or
adding a query to an existing notebook.
* Added notebook search, loading states, and empty-state messaging when
selecting an existing notebook.
  * Saved queries now open in the selected notebook after insertion.

* **Improvements**
  * Added an accessible label to the query title input.
* Updated query-saving controls to appear appropriately when Explorer is
enabled.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 16:26:44 +08:00
Raúl Barroso cad51d85fd docs: give your app an MCP server (BYO-MCP guide rewrite) (#50218)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Fixes AI-1009

Updates the BYO-MCP guide so it includes information about the new
middleware that will let users authenticate much more easily when
building their own MCP server. This one includes a couple of
clarifications which are important to document (use of environment
variables, etc.)

## What is the new behavior?


- Updated the existing guide (and example) for deploying an MCP server
to use `@modelcontextprotocol/server` v2 with `createMcpHandler`.
- Added new bits related to the new middleware which helps with
authentication specifying the required versions of supabase/server and
supabase/middleware, and also the auth prerequisites
- Includes a table of where each MCP client takes the URL.
- Added a new example to
`examples/edge-functions/supabase/functions/mcp/` to illustrate the
authentication example `authenticated-mcp-server`.

## Publish order

> [!IMPORTANT]  
> There will be a companion PR to include the library components so this
PR is blocked until https://github.com/supabase/supabase/pull/49579
ships.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added comprehensive guidance for deploying authenticated MCP servers
with OAuth 2.1, Supabase Auth, and user-scoped data access.
* Added an authenticated MCP server example with `list_todos` and
`create_todo` tools, protected by row-level security.
* Added setup instructions for OAuth configuration, consent screens,
local testing, and deployment.

* **Documentation**
* Updated authentication guidance and MCP security warnings across
related guides.
  * Added links to MCP server and OAuth consent resources.

* **Refactor**
* Simplified the unauthenticated MCP server example and updated its
tooling configuration.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 09:45:14 +02:00
Joshen Lim 1caeb92122 Editor panel fix save snippet (#50262)
## Context

Currently hitting "Save snippet" in the Editor panel doesn't actually do
anything - happening because it's using the legacy `needSaving` queue
logic that we had before manual saving became the default. Tiny fix to
just call `requestSave` instead
<img width="469" height="484" alt="image"
src="https://github.com/user-attachments/assets/66c8fd41-9e7c-44ad-8bb0-cdea8de68bd2"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Improvements**
- Saving a snippet now updates the SQL editor with the latest content
automatically.
- New snippets created from the expanded editor or save dialog are saved
through the standard save flow.

- **Accessibility**
- Added an accessible label to the snippet name field for improved
screen reader support.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 15:35:31 +08:00
Julian Domke 17280319f0 chore(billing): remove invoice type casts (#50338) 2026-09-15 09:16:51 +02:00
Joshen Lim 558bee9ebf Improve SQL Editor auto completion for column names (#48734)
## Context

Currently with the SQL Editor, the auto-completion via intellisense only
works nicely with the `.` operator - e.g after keying in a schema and
trying to find a table as such:
<img width="500" alt="image"
src="https://github.com/user-attachments/assets/86ec8455-47b9-43d3-925a-c13d0fd6ac44"
/>

But lacks support for finding the columns of a table after a `where`
clause - so the changes here addresses that by mainly adjust the
`PgSQLCompletionProvider`

Also addresses a number of type fixes (replaces all the `any` types)

<img width="500" alt="image"
src="https://github.com/user-attachments/assets/e23672a6-2b48-4a98-b300-69f822d12b38"
/>

<img width="415" height="319" alt="image"
src="https://github.com/user-attachments/assets/e6ee64d2-90dd-47d6-9fd2-e8b07821ebb6"
/>



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Improved PostgreSQL SQL editor suggestions with table, column, alias,
schema, and join-aware completions.
* Added context-aware support for statements, quoted identifiers,
subqueries, and qualified columns.
  * Enhanced PostgreSQL function signature assistance.
* Added safer behavior when database metadata is incomplete or
unavailable.

* **Bug Fixes**
  * Prioritized relevant columns and removed duplicate suggestions.

* **Tests**
* Added comprehensive coverage for SQL parsing, metadata handling, and
completion behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 12:34:20 +08:00
Miranda Limonczenko 4d57edd622 docs(database): add data type guidance to the tables guide (#50025)
Refs FDBKIN-4668

Part 5 of a 5-PR stack on
`apps/docs/content/guides/database/tables.mdx`. Builds on #50024.

## Problem

Reader feedback in FDBKIN-4668 reports developers mixing `timestamptz`
and `timestamp` across production schemas for lack of guidance. This PR
adds the guidance half of that ask. The issue also asks for linting in
the schema designer, which is a Frontend change and stays open.

The page listed 44 data types and recommended neither side of any pair a
reader actually has to choose between: `timestamp` or `timestamptz`,
`varchar` or `text`, `numeric` or `float`, `integer` or `bigint`.

No example on the page had a timestamp column at all, and `timestamptz`
appeared only inside the reference table.

## Solution

Adds a short "Choosing a type" section to the Reference group, stating a
safe default for each pair and why.

Also changes `salary bigint` to `salary numeric` in the private schema
example. That line was checked against the wrong-outcome test in #50023
and deliberately left there, because a reader storing cents in a
`bigint` gets a working table. It changes here because **this branch is
what makes it wrong**: once the page recommends `numeric` for money, an
example doing the opposite two screens away teaches the reader the
opposite of what the page just said.

## Manual testing

Preview:
https://docs-git-docs-tables-datatypes-supabase.vercel.app/docs/guides/database/tables#choosing-a-type

1. Open the preview at that anchor. "Choosing a type" renders above the
data type table.
2. Open `#data-types` on the same preview. It still lands on the
reference table, which Studio deep-links to from three components.
3. In a local database, insert `1234.56` into `private.salaries.salary`
and select `salary * 3`. Returns `3703.68` exactly.

## Verification (`test-the-docs`)

Run in the Compose sandbox against a local stack.

| Check | Result |
| --- | --- |
| `create table private.salaries` with `salary numeric` | pass |
| `insert ... values (1234.56, ...)` then `select salary, salary * 3` |
pass — returns `1234.56` and `3703.68`, exact |

The same example failed to run at all before this stack, because
`public.actors` didn't exist on the page's path. #50023 fixes that.




<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Documentation**
- Updated the Postgres tables guide with practical guidance for choosing
column types.
- Added recommendations for timestamps, text, monetary and decimal
values, and identifiers.
- Updated the example salary column to use the `numeric` type instead of
`bigint`.
- Expanded the column type reference section to help readers select
appropriate types for common data.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 19:50:23 -07:00
Ivan Vasilov 944d7730cd chore: Disable the msw logs in Github actions (#50365)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Tests**
  - Reduced diagnostic logging during automated CI test runs.
- Request, mock, and request-handling details remain available in non-CI
environments for troubleshooting.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 10:40:27 +08:00
Danny WhiteandJoshen Lim 1755580dcf feat(studio): move Warehouse setup into Integrations (#50247)
## What kind of change does this PR introduce?

Feature and information architecture change. Builds on #50246.

## What is the current behaviour?

Warehouse setup, progress, errors, table selection, and connection
details all live in the transient Connect sheet. Closing the sheet hides
the current replication state, and the integration is absent from the
Integrations page.

## What is the new behaviour?

Warehouse now has a persistent Overview page at
`/project/{ref}/integrations/warehouse/overview`:

- Before setup, the existing schema and table picker enables Warehouse.
- During setup, the page shows the current phase and per-table backfill
state where available.
- Setup and status failures remain visible on the page with retry
actions where possible.
- Once complete, the page shows Status, Tables, then Connect.
- The Connect sheet becomes read-only. Before Warehouse is ready, it
links directly to the Overview page for setup, progress, or recovery.

| Before | After |
| --- | --- |
| <img width="1200" height="907" alt="Chives Pantry Supabase"
src="https://github.com/user-attachments/assets/82dc7fb0-3859-499e-96ab-56f70a5c7325"
/> | <img width="1200" height="907" alt="Chives Pantry Supabase"
src="https://github.com/user-attachments/assets/7428e301-27f8-48fe-91e0-6880b132920d"
/> |
| <img width="1200" height="907" alt="Chives Pantry Supabase"
src="https://github.com/user-attachments/assets/82dc7fb0-3859-499e-96ab-56f70a5c7325"
/> | <img width="1200" height="907" alt="54709"
src="https://github.com/user-attachments/assets/0c589e5b-e13c-4554-a6ee-6730d0e95c07"
/> |
| <img width="1200" height="907" alt="ETL BigTable ETL Team Supabase"
src="https://github.com/user-attachments/assets/18ec9f6c-3724-453f-bbbb-c7149758246e"
/> | <img width="1200" height="907" alt="Regular AWS Teamer Supabase"
src="https://github.com/user-attachments/assets/3819c9fe-e56d-4cec-988d-5e724f8d990a"
/> |

## To test

Use a project whose organisation is included in the Warehouse
allow-list.

1. Open `/project/{ref}/integrations`, filter by **Data platform**, and
open Warehouse.
2. Before setup, confirm the existing schema and table picker appears
and starts with no tables selected.
3. Start setup and confirm the Status section polls through setup and
table backfill phases.
4. Confirm setup failures remain visible and expose Retry when the API
returns affected tables.
5. After setup, confirm the section order is Status, Tables, Connect.
6. Confirm existing replicated tables are selected and locked, while
additional tables can be added.
7. Open `/project/{ref}?showConnect=true&connectTab=warehouse` and
confirm it links to the Overview page before setup, during setup, and
after a setup failure.
8. Once setup is complete, confirm the Connect sheet shows the FlightSQL
and DuckDB connection controls from #50246.
9. Repeat the Overview checks with **One-Click Integrations** turned
off.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added Supabase Warehouse to the integrations catalog, with overview
documentation and availability-aware display.
* Added Warehouse setup and management flows, including schema and table
selection, replication progress, status details, connection options, and
retry actions.
* Added DuckDB and FlightSQL engine selection with Connect sheet URL and
preference synchronization.
* Added table replication status, lag, timestamps, and size information.

* **Bug Fixes**
* Warehouse setup status requests no longer retry automatically after
failures.
* Improved recovery messaging and retry behavior for setup and
connection errors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-15 12:38:13 +10:00
Joshen Lim ad198b15ab Joshenlim/fe 4376 improve storage log overview and field filtering (#50337)
## Context

Updates the `getValue` for retrieving data from `enrichedData` in
`serviceFlowFields` to pull the appropriate fields for storage logs.

### Before
<img width="403" height="342" alt="image"
src="https://github.com/user-attachments/assets/b9a8e501-79bc-4ed2-ad1e-dd57f55a091e"
/>


### After
<img width="413" height="411" alt="image"
src="https://github.com/user-attachments/assets/8e87c352-ecf8-4246-b5b7-3b4d16274b06"
/>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Expanded log details to display more network, location, technology,
and storage information from available request and response data.
* Added support for additional response-time formats, including valid
zero-duration values.

* **Bug Fixes**
  * Improved truncation and alignment of log detail values.
  * Enhanced accessibility for the “More options” control.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 10:24:18 +08:00
Miranda Limonczenko ef3cfad9ed docs(database): add access control to the tables guide (#50024)
Closes DOCS-1314

Brings the Eval to green.

Part 4 of a 5-PR stack on
`apps/docs/content/guides/database/tables.mdx`. Builds on #50023.

## Problem

The page taught table creation and never said to protect a table. Across
the original 573 lines, "row level security" appeared once, and that
mention was about `security_invoker` on views. There was no `enable row
level security`, no policy, and no `auth.uid()` anywhere.

The gap was uneven between the two paths the page offers. The Table
Editor enables row level security by default and warns that a table
without it is publicly writable and readable. The SQL path on the same
page produced an unprotected table and said nothing about it.

Two further gaps followed from that one:

- **Every example was a single access class.** `movies`, `categories`,
`actors`, `performances`, and `private.salaries` are all the same shape.
The page had no pattern for what most applications actually look like: a
shared table everyone reads sitting beside a per-person table only its
owner reads. The shared one is the one that gets skipped.
- **Nothing told the reader to check the result.** No verify, no
confirm, and no expected output anywhere on the page.

## Solution

Adds a "Securing your tables" section between creating a table and
loading data:

- Enabling row level security and writing a first policy, with the
consequence stated: a table with row level security and no policy
returns no rows to anyone.
- A worked example with two access classes, `movies` and `watchlists`.
- A verification step. Two queries against `pg_tables` and `pg_policies`
confirm that every table exists, has row level security enabled, and has
at least one policy.

Policy examples follow the idioms in the Row Level Security guide,
including the wrapped `(select auth.uid())` form. The guide is
cross-referenced rather than restated.

## Verification (`test-the-docs`)

All 22 SQL fences on the page were run in document order against a local
stack, the way a reader pasting top to bottom would.

| Snippet / step | Class | Result | Notes |
| --- | --- | --- | --- |
| `create table movies` (Creating tables) | runnable-local | pass | |
| `create table movies` ×2 (Primary keys) | illustrative-only | skipped
| Re-shows the same table to explain `identity`; not a continuation |
| `alter table movies enable row level security` | runnable-local | pass
| |
| `create policy "Anyone can read movies"` | runnable-local | pass | |
| `create table watchlists` + 2 policies | runnable-local | pass | |
| Verification query, `pg_tables` | runnable-local | pass | Lists both
tables with `rowsecurity` true |
| Verification query, `pg_policies` | runnable-local | pass | Lists all
three policies |
| `insert into movies` (Basic data loading) | runnable-local | pass | |
| `create table categories` + foreign key | runnable-local | pass | |
| `create table actors` / `performances` | runnable-local | pass |
Failed before this stack; see below |
| `create schema private` | runnable-local | pass | |
| `create table private.salaries` | runnable-local | pass | Failed
before this stack; see below |
| Views section, 9 fences | illustrative-only | skipped | Depend on
`students`, `courses`, and `grades`, which the page shows as rendered
tables and never creates |

**Tier A path:** `movies` → enable RLS → policy → `watchlists` +
policies → both verification queries → `insert into movies` →
`categories` + FK → `actors`/`performances` → `private` schema →
`private.salaries`. Runs clean end to end.

**Tier B, RLS behavior.** Every access claim in "Securing your tables"
was exercised with two real users:

| Check | Expected | Observed |
| --- | --- | --- |
| User A inserts into their own watchlist | succeeds | succeeds, A sees
1 row |
| User B reads A's rows | 0 rows | 0 rows |
| `anon` reads `movies` | rows returned | 2 rows |
| `anon` reads `watchlists` | 0 rows | 0 rows |
| User B inserts a row owned by A | rejected | `new row violates
row-level security policy for table "watchlists"` |

**Environment:** Compose sandbox (`sandbox/run.sh up-stack`), DinD +
`supabase start`, Postgres 17. Fences ran in-container only, never on
the host.

**Note on the sandbox.** `supabase start` inside the nested daemon hit
repeated `toomanyrequests: Rate exceeded` from ECR Public. The CLI
retries and the stack does come up, but expect a slow first run.

## What this PR leaves to the one above it

Data type guidance is #50025.

## Manual testing

Preview:
https://docs-git-docs-tables-rls-supabase.vercel.app/docs/guides/database/tables#securing-your-tables

1. Open the preview at that anchor. The three subsections render, and
the numbered steps show their embedded SQL blocks.
2. In a local project, run the `movies` and `watchlists` snippets, then
the two verification queries. Both tables appear with `rowsecurity` true
and at least one policy each.
3. As a signed-out client, select from `movies` and from `watchlists`.
`movies` returns rows; `watchlists` returns none.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Documentation**
- Expanded the database tables guide with instructions to secure tables
before adding rows.
- Added guidance on enabling row-level security and creating policies
for shared and per-person tables.
- Clarified that policies control row access, while revoked table grants
can cause permission errors.
- Documented owner-scoped access using authenticated user IDs and ways
to verify table protection.
- Explained that read-only policies reject inserts through the Data API
and provided alternatives.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 18:49:11 -07:00
Miranda Limonczenko 31a0f450cf docs(database): correct the Dashboard table creation steps (#50023)
Part 3 of a 5-PR stack on
`apps/docs/content/guides/database/tables.mdx`. Builds on #50022.

## Problem

Three claims fail the test that a reader following the page would hit a
wrong outcome.

**The Dashboard steps don't match the product.** They said to click
**New Table**, save, then click **New Column**. Columns are defined
inside the table creation panel, so a reader who follows the steps saves
a table with no columns and then hunts for a button that isn't part of
that flow. The labels are also sentence case in the product: **New
table** and **New column**.

**The Dashboard example diverges from the rest of the page.** The steps
created a table named `todos` with a `task` column, while the SQL tab
beside them and every later example use `movies`. A reader who took the
Dashboard path and then ran the first Loading data snippet got `relation
"movies" does not exist`.

**The page's SQL doesn't compose.** Running every fence in document
order showed that the many-to-many example under "Joining tables with
foreign keys" opened by creating `movies` again. A reader who already
created it got `relation "movies" already exists`, the block stopped, so
`actors` was never created, and the `private.salaries` example two
sections later then failed with `relation "public.actors" does not
exist`. **One redundant statement broke two sections.**

**The bulk loading example couldn't work.** `COPY` accepts text, CSV,
and binary input, and the page listed JSON. `\COPY movies FROM
'./movies.csv'` expects a value for every column, and `movies` has three
while the sample file has two. The options example passed `CSV HEADER`
against a file with no header row, which silently dropped the first
record. Found by CodeRabbit.

## Solution

Rewrites the five Dashboard steps to match the panel and to produce
`movies`, so both tabs leave the reader in the same place. Drops the
redundant `create table movies` from the many-to-many block; the prose
above it already says "You have a list of `movies`". Names the columns
in both `COPY` commands, corrects the format list, points the `HEADER`
example at a file that has one, and removes the space before each quoted
CSV field.

Dashboard changes verified against `TableEditor.tsx`, which renders
`ColumnManagement` inside the creation panel; `TableEditorMenu.tsx` and
`ColumnList.tsx` for the labels; and `DEFAULT_COLUMNS` in
`TableEditor.constants.ts` for the `id` and `created_at` columns the
editor adds.

## Checked and deliberately left

- `grant all on table transcripts to authenticated`. Broader than the
example needs, but a reader gets the working result the page promises,
so it doesn't meet the bar for this branch.
- "By default, views are accessed with their creator's permission."
Accurate. `security_invoker` is opt-in.
- `salary bigint` in the private schema example. Left here; it changes
in #50025, where the page starts recommending `numeric` for money and
the example becomes inconsistent with it.

## Flagged, not changed

- The `api-create-table-sm.mp4` video in the Dashboard tab may show the
older flow. Its contents weren't verified.
- **Nothing in the Views section is runnable.** All nine of its fences
depend on `students`, `courses`, and `grades`, which the page shows as
rendered tables and never creates. Supplying that DDL is new content, so
it isn't this branch's job, but it's worth a ticket.

## Manual testing

Preview:
https://docs-git-docs-tables-technical-supabase.vercel.app/docs/guides/database/tables

1. Open the preview and read the Dashboard tab under "Creating tables".
It says **New table**, creates `movies`, and defines both columns in the
same panel.
2. Open the Table Editor in a project and click **New table**. The panel
has a **Name** field and a **Columns** section, and there is no separate
**New Column** step.
3. In a fresh local database, run the SQL fences from "Creating tables"
through `private.salaries` in page order. Each one succeeds.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Documentation**
- Updated the “Creating tables” guide to use a `movies` table with
`name` and `description` columns.
- Reworded and consolidated the table-creation steps, including the
`created_at` column in the SQL example.
- Updated bulk data loading instructions for CSV imports, connection
setup, named columns, and header-delimited files; removed JSON from the
listed formats.
- Simplified the many-to-many example by removing the redundant `movies`
table definition.
  - Clarified schema selection based on the current `search_path`.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 17:32:36 -07:00
Danny White 2e435986c9 feat(studio): polish the Replication pipelines list (#50252)
## What kind of change does this PR introduce?

Studio UI and interaction polish. This is the second PR in the Pipelines
review stack and depends on #50251.

## What is the current behaviour?

Pipeline rows require a separate view action, cannot be sorted, and
present lifecycle, lag, and destination terminology inconsistently.

## What is the new behaviour?

Makes rows navigable with link-like mouse and keyboard behaviour, adds
Name and Status sorting, reuses cached status queries, and moves row
actions into the overflow menu. It also clarifies pipeline terminology,
adds Docs and feedback actions, and standardises state, error, lag, and
loading presentation with accessible announcements.

| Before | After |
| --- | --- |
| <img width="1280" height="1323" alt="Replication Database ETL BigTable
ETL Team Supabase"
src="https://github.com/user-attachments/assets/53a62283-0e58-4408-8409-2b87a38af159"
/> | <img width="1280" height="1323" alt="Replication Database Agua
Basket Supabase"
src="https://github.com/user-attachments/assets/ba4de1e0-4a84-43b4-8975-ca05a3056bcf"
/> |

## To test

1. Open `/project/<ref>/database/replication`.
2. Sort by Name and Status, then confirm failed and stopped pipelines
surface first when Status is ascending.
3. Click a row, use Enter or Space, and modifier-click or middle-click
to verify link behaviour.
4. Open the row overflow menu and confirm it does not navigate.
5. Check loading, initial sync, caught up, numeric lag, unavailable lag,
and table-error states where available.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added sortable pipeline lists with clearer loading, empty, and error
states.
- Pipeline rows now support direct navigation, detail viewing, status
indicators, lag progress, and table error summaries.
- Added initial-sync progress indicators and accessible status
announcements.
  - Added documentation and feedback links.
  - Improved pipeline version update and enable/disable dialogs.

- **Bug Fixes**
  - Prevented right-clicks from triggering navigation.
  - Improved unavailable lag and initial-sync handling.

- **Style**
- Standardized replication terminology and confirmation messaging around
pipelines.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-15 10:07:49 +10:00
74c116de74 docs: add Multigres Public Alpha documentation — MERGE ON SEP 14, 2026 (#49020)
## I have read the CONTRIBUTING.md file.

YES

## What kind of change does this PR introduce?

This PR adds Public Alpha documentation for Multigres, Supabase's
multi-node Postgres high-availability integration. It introduces an
overview guide, a compatibility stub, Database sidebar navigation, a
Features table row, and a "What you get" card grid. ContentListings
items can now omit `href` so those cards are not forced to be links.

Linear: MUL-452.

~~🚨 **DO NOT MERGE UNTIL THE PUBLIC ALPHA GOES LIVE** 🚨~~ [@jhydra12
OK'ed merging, FYI]


## What is the current behavior?

- Linear item: Documentation for Multigres
- Production has no Multigres guides.
`https://supabase.com/docs/guides/database/multigres` and
`https://supabase.com/docs/guides/database/multigres/compatibility`
return 404
- The Database sidebar has no Multigres section
- The Features status table does not list Multigres
- ContentListings items required a link (`href` was mandatory)

## What is the new behavior?

- Overview guide at `/docs/guides/database/multigres` covering alpha
status, eligibility, enablement, and what is not included
- Compatibility stub at `/docs/guides/database/multigres/compatibility`
- Database sidebar: Multigres → Overview, Compatibility (after OrioleDB)
- Features table: Database / Multigres / `public alpha`
- "What you get" renders as three non-link ContentListings cards
- `href` is optional on ContentListings items; markdown export renders
unlinked entries when it is omitted

## Additional context

- Worktree:
~/GitHub/supabase/supabase-worktrees/nikrichers/mul-452-documentation-for-multigres-ready
- Branch commits: Initial Multigres docs draft; Edits (cards, copy, MDX
comments); merge master; spelling allow-list for Multigres, Vitess, and
sharding

- Verification:

| Check                                   | Result          |
| --------------------------------------- | --------------- |
| Preview overview                        | 200             |
| Preview compatibility                   | 200             |
| Production overview                     | 404 (expected)  |
| Production compatibility                | 404 (expected)  |
| `supa-mdx-lint` on changed MDX          | pass            |
| `vitest` `lib/content-listings.test.ts` | pass (21 tests) |

### Proof: Multigres docs pages render, including non-link What you get
cards

**Verified:** production 404 · Vercel docs preview 200

#### Overview [(PR
preview)](https://docs-git-nikrichers-mul-452-documentation-for-m-6f8a59-supabase.vercel.app/docs/guides/database/multigres)

<img width="1388" height="2272" alt="image"
src="https://github.com/user-attachments/assets/2780f728-07c0-4320-9826-8f6e68df21e6"
/>

#### Compatibility [(PR
preview)](https://docs-git-nikrichers-mul-452-documentation-for-m-6f8a59-supabase.vercel.app/docs/guides/database/multigres/compatibility)

<img width="1388" height="852" alt="image"
src="https://github.com/user-attachments/assets/1f8f7181-5b7d-4d01-b376-a2eac923626b"
/>

### Test plan

- [ ] [Production
overview](https://supabase.com/docs/guides/database/multigres) (404) vs
[preview
overview](https://docs-git-nikrichers-mul-452-documentation-for-m-6f8a59-supabase.vercel.app/docs/guides/database/multigres)
- [ ] [Production
compatibility](https://supabase.com/docs/guides/database/multigres/compatibility)
(404) vs [preview
compatibility](https://docs-git-nikrichers-mul-452-documentation-for-m-6f8a59-supabase.vercel.app/docs/guides/database/multigres/compatibility)
- [ ] Database sidebar shows Multigres → Overview and Compatibility
after OrioleDB
- [ ] Overview shows Public Alpha caution, three What you get cards (not
links), eligibility, and one-way-migration caution
- [ ] Compatibility page is a placeholder that links back to the
overview
- [ ] Features table lists Database / Multigres / `public alpha`
- [ ] `supa-mdx-lint` on
`apps/docs/content/guides/database/multigres.mdx`,
`apps/docs/content/guides/database/multigres/compatibility.mdx`, and
`apps/docs/content/guides/getting-started/features.mdx`


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added Multigres documentation covering availability, setup,
compatibility, limitations, migration behavior, and external resources.
  * Added Multigres to database navigation and feature-status listings.
* Added an overview of Multigres benefits, including automatic failover,
unchanged connection strings, and consensus-backed write durability.

* **Improvements**
* Content listings now support informational items without links across
layouts.
* Improved listing rendering and click tracking for linked and
non-linked items.

* **Documentation**
* Added spelling support for Multigres, Vitess, and sharding
terminology.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Nik Richers <nik@validmind.ai>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-09-15 09:48:39 +10:00
Miranda Limonczenko 5979218c97 docs(database): split out views and group the tables guide by information type (#50022)
Part 2 of a 5-PR stack on
`apps/docs/content/guides/database/tables.mdx`. Builds on #50021.

## Problem

Four structural problems, all covered by the Guides section of
CONTRIBUTING.

**Views was a second topic living inside a guide about tables.** Roughly
180 lines, its own subsections four levels deep, sharing nothing with
the tables above it beyond the word "table".

**The page didn't say what it was for.** It opened with three paragraphs
and a sample table before a reader could tell whether the page matched
their goal. CONTRIBUTING asks a guide to begin with a sentence declaring
its intent.

**The top level mixed information types.** It was a flat list of every
task, so "Schemas" and "Primary keys" sat beside "Creating tables" and
background interrupted the action path.

**Reference material interrupted the procedure.** A 44-row data type
table sat between "Creating tables" and "Loading data", so a reader
following the action path walked through it.

Plus a duplicate video: the Dashboard tab under "Joining tables with
foreign keys" embedded the same YouTube ID that frontmatter already
serves as the table of contents video.

## Solution

Moves and regrouping.

- **Views moves to its own page**, `guides/database/views`, with its
headings promoted one level and the two view-related links from
Resources moved with it.
- The page opens with an intent sentence, then a section outline, then a
"What is a table?" section holding the definition and the spreadsheet
comparison.
- The remaining sections split into three groups by information type,
ordered procedures, context, reference: **Creating and managing tables**
holds creating, loading, and joining; **How tables are organized** holds
primary keys, relationships, and schemas; **Reference** holds the data
type table.
- "Joining tables with foreign keys" held both classes, so it splits.
The steps keep the heading and stay in the procedures group. The
concept, what relational means and the diagram showing it, becomes
**Relationships between tables** in the context group. The two
cross-reference each other.
- The duplicate video goes, and with the Dashboard tab empty the
surrounding `Tabs` wrapper goes too.

## Anchors

**Every heading keeps its text, so every anchor keeps its slug.**
Demoting a heading changes its level, not its anchor. That matters
because the inbound links are mostly outside `apps/docs`: Studio
deep-links to `#data-types` from three components and `#primary-keys`
from two, and `apps/www` links to `#creating-tables` and
`#joining-tables-with-foreign-keys`.

`#views` is the one exception, since that content left the page. Its
single inbound link, in `guides/ai/engineering-for-scale.mdx`, now
points at the new page, and both `NavigationMenu.constants.ts` entries
are updated: the existing item becomes "Managing tables and data" and a
"Views" item sits beside it.

## One deletion that isn't a move

The "Columns" heading and its one sentence, "You must define the data
type when you create a column." The heading held only the two
subsections that moved out, and the sentence repeats a line 50 lines
above it.

## Deferred

Reordering "View security" behind an access-control foundation. That
move only reads correctly once the foundation exists, so it travels with
that content in #50024.

## Manual testing

Preview:
https://docs-git-docs-tables-structure-supabase.vercel.app/docs/guides/database/tables

1. Open the preview. The page opens with its intent, then a four-entry
outline, then "What is a table?". Each outline link resolves, and the
three groups below read as procedures, then context, then reference.
2. Open `#data-types`, `#primary-keys`, `#creating-tables`, and
`#joining-tables-with-foreign-keys` on the preview. All four still land
on their sections.
3. Open
https://docs-git-docs-tables-structure-supabase.vercel.app/docs/guides/database/views.
The new page renders, and "Views" appears in the sidebar beside
"Managing tables and data".
4. Run `pnpm build:guides-markdown` from `apps/docs`. It generates 782
files, one more than before. Discard the change to
`public/markdown/manifest.json`, which the repo commits as `[]`.



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Documentation**
- Added a dedicated guide covering Postgres views, including creation,
querying, security options, and materialized views.
- Reorganized the Tables and data guide with clearer sections,
navigation links, table organization details, and reference information.
  - Updated the many-to-many example to display SQL directly.
- Split database navigation into separate “Managing tables and data” and
“Views” entries.
- Added a PostgreSQL log configuration entry and a C# client reference
link.
  - Updated documentation links to point to the new Views guide.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 16:43:05 -07:00
Miranda Limonczenko e022145be9 docs(database): apply house style to the tables guide (#50021)
Part 1 of a 5-PR stack on
`apps/docs/content/guides/database/tables.mdx`, one change type per PR.

## Problem

The page addressed the reader as "we" in about 18 places. CONTRIBUTING
reserves `we` for the Supabase team and asks that the reader be `you`.
None of it was caught by the linter, because
`Rule004ExcludeWords/first_person` only bans singular first person.

Alongside that: scare quotes on established terms, parenthetical asides
that CONTRIBUTING disallows, future tense where present tense reads
better, an ordered list that repeated `1.` four times, and three
relative links where `/docs/...` paths belong.

**The three diagrams had alt text that named a topic instead of
describing the picture.** "Schemas and tables" tells a screen reader
nothing about a diagram showing two schema boxes, one labeled `public`
holding six tables and one labeled `api` holding three.

## Solution

Inline rewrites and cuts. **Nothing in this PR moves a line from one
place to another.**

Each alt now describes its diagram: the column types in the table
diagram, the arrow between matching columns in the foreign key diagram,
and the two labeled schemas with their table counts.

Two deletions worth calling out:

- The `<br />` spacer after the data type table.
- The four-item benefits list under "When to use views". The four
headings immediately below restate it verbatim.

Also fixes "Every column is a predefined type", which states the
relationship backwards. A column has a type; it isn't one.

## One dead link, surfaced by the conversion

The Loading data intro pointed at `guides/database/api`, which isn't a
page. It exists only as a redirect in `apps/www/lib/redirects.js`, and
that redirect doesn't serve the docs deployment, so the link 404s there.
As a relative link it was invisible to the link checker; converting it
to a `/docs/...` path is what made the Docs E2E suite catch it.

It now points at `/docs/guides/api`, the live page that 13 other guides
already link to.

## What this PR leaves to the ones above it

Section moves and the Views page split are #50022. Corrections to claims
are #50023. New content is #50024 and #50025.

## Manual testing

Preview:
https://docs-git-docs-tables-style-supabase.vercel.app/docs/guides/database/tables

1. Open the preview. The intro reads "Excel spreadsheets" and
"relational databases", and the only remaining "we" is "We provide a SQL
editor within the Dashboard", which refers to Supabase rather than the
reader.
2. Inspect the three images on the preview. Each `alt` describes the
diagram rather than naming its topic.
3. Follow the **Data API** link under "Loading data". It resolves
instead of returning 404.
4. Run `npx prettier --check
apps/docs/content/guides/database/tables.mdx` and `pnpm lint:mdx` from
`apps/docs`. Both pass.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Documentation**
- Clarified guidance on table creation, data types, primary keys, bulk
loading, relationships, schemas, views, and materialized views.
- Improved wording, capitalization, terminology, and internal navigation
throughout the tables guide.
  - Updated diagram alt text with more descriptive captions.
  - Updated the loading data section to link to the Data API guide.
- Revised the bulk-loading example with an explicit column list, CSV
options, and a simplified database connection command.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 16:31:11 -07:00
Ali Waseem 2cd9b42e80 fix(studio): add a keyboard shortcut for the Compute sidebar item (#50361)
The Compute entry in the project sidebar was the only product route
without a `shortcutId`, so it had neither a `G`-chord nor the hover
keybind tooltip every sibling gets. Bound it to `G` then `C` (previously
unused) and added a test asserting every product route carries a
shortcut.

Fixes FE-4389

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Added a keyboard shortcut for quick navigation to Compute: press
**G**, then **C**.
- Compute navigation now includes a discoverable shortcut for consistent
access from the navigation interface.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 19:44:40 +00:00
bd95407a9c fix(ui): validate stored resizable-panel layout before handing it to react-resizable-panels (#50349)
## Summary
- `serverCompatibleLocalStorage.getItem()` already guards against
localStorage access itself throwing (SSR, private browsing, sandboxed
iframes), but returns whatever string is stored without checking it's
valid JSON.
- `react-resizable-panels`' own `useDefaultLayout()` calls
`JSON.parse()` on that value with no try/catch, so a stored value that
isn't valid JSON (overwritten by another script sharing the origin, a
browser extension, or a leftover value from a previous format) throws
and crashes the whole panel group instead of falling back to the default
layout.
- Fix: validate the value is parseable JSON in `getItem()` itself
(matching the file's existing best-effort persistence philosophy) and
return `null` — same as a missing value — when it isn't.

## Evidence (Sentry, past week)
- [SUPABASE-APP-KA8](https://supabase.sentry.io/issues/7726278966/) —
`SyntaxError: Unexpected token 'K', "KV-OK" is not valid JSON`,
full-page crash via `globalErrorBoundary` on `/project/[ref]/sql/[id]`.

## Test plan
- [ ] Manually confirmed the existing `transformLayoutKey`/try-catch
behavior for a missing or inaccessible key is unchanged
- [ ] Considered adding a unit test for
`serverCompatibleLocalStorage.getItem()`, but it isn't currently
exported; happy to export it and add a test if reviewers want one

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

https://claude.ai/code/session_01RUrmUfMBpPqkgerh9onNTM

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-09-14 13:39:54 -06:00
8bbd1d3048 fix(studio): fall back to unified preset for an unrecognized query-performance preset (#50348)
## Summary
- `useIndexInvalidation()` resolves the `preset` URL param through
`QUERY_PERFORMANCE_PRESET_MAP` with no fallback.
- A value that isn't one of the four known
`QUERY_PERFORMANCE_REPORT_TYPES` (stale bookmark, hand-edited URL, a
renamed/removed preset) resolves to `undefined`.
- That `undefined` preset flows into `generateQueryPerformanceSql()`,
which indexes `queryPerfQueries.queries[preset]` with it, producing
`undefined` for `baseSQL` — and the very next line reads
`baseSQL.queryType`, crashing the whole page via `globalErrorBoundary`.
- Fix: fall back to the `unified` preset when the URL value doesn't map
to a known preset, mirroring the `parseAsString.withDefault('unified')`
intent already expressed a few lines above for the case where the param
is entirely absent.

## Evidence (Sentry, past week)
- [SUPABASE-APP-K9Z](https://supabase.sentry.io/issues/7721026586/) —
`TypeError: Cannot read properties of undefined (reading 'queryType')`
on `/dashboard/project/[ref]/observability/query-performance`.

## Test plan
- [ ] Existing `useQueryPerformanceQuery.test.ts` suite still passes
- [ ] Manually confirmed
`QUERY_PERFORMANCE_PRESET_MAP[QUERY_PERFORMANCE_REPORT_TYPES.UNIFIED]`
resolves to `'unified'`, a valid key in
`PRESET_CONFIG[Presets.QUERY_PERFORMANCE].queries`

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

https://claude.ai/code/session_01RUrmUfMBpPqkgerh9onNTM

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-09-14 13:28:24 -06:00
Miranda Limonczenko bc917370d1 docs: recommend a local CLI install on the front page (#50356)
Closes DOCS-1391

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Docs update.

## What is the current behavior?

The docs front page is the only place that still recommends a global CLI
install. It shows `npm install -g supabase` in both the CLI tab and the
AI prompt, and tells the agent to run `supabase init`.

Everywhere else in the docs installs the CLI as a project dev
dependency, so the version is pinned in `package.json` and everyone on a
team runs the same one.

## What is the new behavior?

- `installCli` becomes `npm install supabase --save-dev`, matching
[Install and run the
CLI](https://supabase.com/docs/guides/local-development/cli/getting-started).
- `initialize` becomes `npx supabase init`. A dev-dependency install
leaves no global `supabase` command.
- The AI prompt says "as a project dev dependency" and states the
reason, so an agent doesn't fall back to a global install.
- Updates the same wording in the monitoring and debugging prompt, which
shares the constants.
- Updates the `AiPrompt` markdown schema test assertion.

## Manual testing

1. Open the [docs front page
preview](https://docs-git-docs-cli-local-install-supabase.vercel.app/docs).
The AI Prompt tab reads "Install the Supabase CLI as a project dev
dependency with `npm install supabase --save-dev`, so the version is
pinned per project" and ends with `npx supabase init`.
2. Select the **CLI** tab. It shows `npm install supabase --save-dev` on
the first line and `npx plugins add supabase-community/supabase-plugin`
on the second.
3. Run `pnpm run -F docs test:local:unwatch
internals/markdown-schema/AiPrompt.test.ts`. All tests pass.
2026-09-14 12:21:59 -07:00
Prashant Sridharan c38117b613 Added new go page for CISO dinner at Select (#50360)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Added a CISO dinner landing page and integration with Notion.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added an RSVP page for the Supabase Select 2026 CISO Dinner in San
Francisco.
* Included event details, host information, attendee fields, and RSVP
submission with confirmation redirect.
* Added a thank-you page confirming successful registration and sharing
event timing and security resources.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 20:20:43 +01:00
c3ccf9179f fix(www): skip the careers-page globe when WebGL is unavailable (#50350)
## Summary
- `cobe`'s `createGlobe()` resolves the canvas context internally as
`getContext('webgl2') || getContext('webgl') || 'experimental-webgl'` (a
context-name *string*, not an actual context). When both `webgl2` and
`webgl` are unavailable, it falls through to that string, but modern
browsers no longer support the `experimental-webgl` context name, so the
resulting context is `null` and cobe crashes internally reading
`.enable(...)` on it.
- `apps/www/components/Globe.tsx` (used only on `/careers`) had no guard
for this, so a browser/device with WebGL disabled or unavailable (GPU
blocklist, corporate policy, privacy setting) crashes the entire careers
page via `globalErrorBoundary`.
- Fix: detect WebGL support ourselves (`getContext('webgl2') ||
getContext('webgl')`) before mounting the globe, and skip rendering it
(no globe, rest of the page renders fine) when unsupported.

## Evidence (Sentry, past week)
- [WWW-41](https://supabase.sentry.io/issues/7731263201/) — `TypeError:
Cannot read properties of null (reading 'enable')` on `/careers`, leaf
frame inside `cobe`/`phenomenon`.

## Test plan
- [ ] Manually confirmed `Globe.tsx` is only imported by
`apps/www/pages/careers.tsx`
- [ ] No automated test added (this is a purely decorative,
non-interactive canvas element with no existing test coverage); happy to
add one if reviewers want it

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

https://claude.ai/code/session_01RUrmUfMBpPqkgerh9onNTM

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-09-14 13:20:02 -06:00
62fe0fca4a fix(studio): guard branches and read-replicas queries against non-array 200 bodies (#50347)
## Summary
- `getBranches()` (`apps/studio/data/branches/branches-query.ts`) and
`getReadReplicas()` (`apps/studio/data/read-replicas/replicas-query.ts`)
cast the raw API response body to an array with no runtime check.
- When the endpoint returns a defined-but-non-array 200 body, the `??
[]` fallback in each consumer doesn't catch it (the value isn't
nullish), and the first `.find`/`.filter` call throws, crashing the
whole page via `globalErrorBoundary`.
- This is the same known class of bug already fixed elsewhere in the
codebase (e.g. `apps/studio/data/lint/lint-query.ts`, and the
`api-keys`/`oauthApps`/`secrets` fetchers) — applies the same
`Array.isArray(data) ? data : EMPTY_ARR` guard.

## Evidence (Sentry, past week)
- [SUPABASE-APP-KA2](https://supabase.sentry.io/issues/7722780387/) —
`(m??[]).find is not a function` in `ActivityStats.tsx`
(`branchesData.find`), full-page crash on `/dashboard/project/[ref]`.
- [SUPABASE-APP-KAE](https://supabase.sentry.io/issues/7729679561/) —
`u.filter is not a function` in `AWSPrivateLinkForm.tsx`
(`databases.filter`), full-page crash on
`/project/[ref]/settings/integrations`.

## Test plan
- [ ] Existing query hook tests still pass
- [ ] Manually verified `Array.isArray` guard mirrors the established
`lint-query.ts` pattern

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

https://claude.ai/code/session_01RUrmUfMBpPqkgerh9onNTM

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
2026-09-14 19:16:41 +00:00
Sean Oliver d439ba57f4 feat(studio): mask HTML attributes in session replay (#48818)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Hardening ahead of any decision to enable session replay, plus a
dependency bump. Follow-up to #48515.

### What's inside

- ~50 lines of logic: the callback, the `url()` pattern, and the theme
and SVG-reference gates
([session-replay.ts](https://github.com/supabase/supabase/pull/48818/changes#diff-b7e4f10387ee7a116dd1673f70a55c0ba066687ff2d228bc2320eba75a349fac))
- ~170 lines of allowlist, one attribute name per line, skimmable ([same
file](https://github.com/supabase/supabase/pull/48818/changes#diff-b7e4f10387ee7a116dd1673f70a55c0ba066687ff2d228bc2320eba75a349fac))
- ~150 lines of comments saying why each group is allowlisted, since a
wrong entry is a privacy or a fidelity bug ([same
file](https://github.com/supabase/supabase/pull/48818/changes#diff-b7e4f10387ee7a116dd1673f70a55c0ba066687ff2d228bc2320eba75a349fac))
- ~430 lines of tests, one case per policy decision
([session-replay.test.ts](https://github.com/supabase/supabase/pull/48818/changes#diff-f9feb872ad0136cf87c7e9fb2af72eb3f4019464c06f0b7dd050ffb85373ccb8))
- 1 line of dependency bump, plus its lockfile
([package.json](https://github.com/supabase/supabase/pull/48818/changes#diff-50d7c39a9430d37971aa76858165ab4f7921c4cc4340b28e9b673ce6982e63cf))

## What is the current behavior?

Session replay is disabled in every environment, and no recordings
exist. This is about what a recording *would* contain if it were ever
switched on.

Attributes are the one channel replay masking cannot reach. `maskTextFn`
only sees DOM text nodes, so a component interpolating customer data
into a `placeholder`, `title` or `aria-label` would be captured
verbatim. Before `posthog-js` 1.413.0 there was no hook for it at all,
and the only mitigation was blocking the element, which drops it from
the capture entirely.

Two places in Studio where that would apply:

- `CreateOrUpdateCustomProviderSheet.tsx:506-507` interpolates the
project's API host into both `value` and `placeholder`. The `value` is
masked. The `placeholder` is not.
- `FileExplorerHeader.tsx:185` renders `Search in
${currentFolderName}...`, a customer storage folder name.

The list is not complete. Any component echoing context into a tooltip
reproduces it, and the author has no reason to be thinking about replay.

Linear [GROWTH-1094](https://linear.app/supabase/issue/GROWTH-1094).
Blocks [GROWTH-1073](https://linear.app/supabase/issue/GROWTH-1073).

## What is the new behavior?

`maskAttributeFn` with a default-deny policy: an allowlist of the
attributes replay needs to render, everything else masked.

### Policy edge cases

- **rrweb's `rr_*` layout attributes have to be allowlisted
explicitly.** posthog-js only applies its own exemption for those when
`maskAllElementAttributes` does the masking. A callback does not get the
exemption.
- **HTML `id` is masked. SVG `id` passes.** `AreaChart.tsx:119` emits
`<linearGradient id="colorUv">` and references it as
`fill="url(#colorUv)"`, so masking it breaks the gradient. But Studio
also binds customer-named values to `id` (`bucket.id` is a storage
bucket name). Split on `element.namespaceURI`.
- **SVG reference attributes pass only fragment-only targets.** recharts
clips every series with `clip-path="url(#clipPath-<id>)"`, so
`clip-path`, `mask`, `filter`, `marker-*`, `fill` and `stroke` have to
survive. They accept external URLs too, so the policy checks the target
rather than allowlisting the attribute name.
- **The `url()` pattern consumes escaped delimiters and ignores case.**
A target containing a quote serializes as `\"` and one containing a
bracket as `\)`, so a naive `[^")]*` stops at the backslash and leaves
the tail of the URL recorded. `URL(...)` is the same function as
`url(...)`. A token the pattern cannot parse falls through to a masking
fallback rather than passing.
- **`url()` targets inside `style` are masked, keeping the
declarations.** The feedback widget puts `toPng(document.body)`, a
base64 PNG of the whole dashboard, into a `background-image`, and the
storage preview panes put signed object URLs there. No other masking
path covers those, because they are not text nodes, a canvas, a network
request or an `img src`.

The config also pins `maskAllElementAttributes: false`. Left unset it
resolves from the PostHog UI, and `true` discards `maskAttributeFn`
entirely.

The `posthog-js` floor rises to `^1.416.1`, the first version carrying
both attribute masking and the "coarse option wins" precedence.

This does not enable recording anywhere.

## Additional context

### Verification

Ran on the studio-staging preview against a live session: 817 seconds,
190 clicks, 82 keypresses. Staging has no server-side masking config, so
everything masked came from this code.

| Check | Result |
|---|---|
| Storage folder search placeholder | Asterisked. Pre-fix it read
`Search in <folder>...` |
| Custom auth provider sheet | Fully masked, including the callback URL
field |
| Canary folder name in event properties | 0 hits, with 51 events in the
session as the control |
| Console capture | `console_log_count: 0` despite the project having
`capture_console_log_opt_in: true` |
| Telemetry regression | None: `$pageview` x34, `$pageleave` x5,
`$groupidentify` x4, `$identify` x1 |

Recording was scoped to that one preview by an origin restriction plus a
URL trigger. Both were reverted afterwards along with the project
toggle.

The policy has 175 unit tests. Separately, the config was bundled with
esbuild and applied to a DOM reproducing Studio's serialized output (the
AreaChart gradient, a recharts `clip-path`, a lucide icon, an inline
`background-image`), and the chart, gradient fill and icon come out
pixel-identical.

### Known fidelity costs

- `img src` is masked, so images don't render in replay. Storage object
URLs are signed customer content.
- `ProviderIcon` renders its mark as `maskImage: url(<src>)` and
`normalizeIconPath` accepts absolute URLs, so provider icons don't
render either.

### Out of scope

rrweb records `<style>` element text without calling either masking
function, because its text-node serializer skips masking when the parent
is `STYLE`. This PR does not reach that channel. Fixed separately in
#50270 / [GROWTH-1229](https://linear.app/supabase/issue/GROWTH-1229).

`captureJsonLd` also defaults on as of PostHog's 2026-08-30 defaults,
which is a capture channel masking doesn't reach. Studio renders no
`ld+json`, so it's inert there, and pinning it off was left out to keep
this PR to its scope.

### The allowlist is the weak part

The policy is default-deny over attribute *names*, so its surface is
every attribute any shipped library emits, and that set grows with each
dependency. A miss is also invisible to these tests, which assert what
the function returns rather than whether some selector elsewhere still
matches. Both failure directions are reachable that way: an attribute
carrying customer data, and an attribute a stylesheet needs.

[GROWTH-1232](https://linear.app/supabase/issue/GROWTH-1232) tracks the
mechanism change: scope by namespace instead of by name, since 50 of the
159 entries exist only to serve SVG rendering, plus a conformance test
that derives the expected set from the codebase so a new dependency
fails CI rather than degrading a replay. Deliberately not done here,
since rewriting the mechanism of a privacy control buys maintainability
rather than correctness.
2026-09-14 09:48:58 -07:00
Sean Oliver 32f17f994d fix(studio): key query chart series by position, not column name (#50270)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Bug fix. Hardening ahead of any decision to enable session replay.

### What's inside

- ~47 lines of logic: positional series keys, the X-key collision guard,
and the rewiring of rows, cumulative results and axis width
([QueryResultChart.tsx](https://github.com/supabase/supabase/pull/50270/changes#diff-dae994728613498678bcc06a3ea5176b36708e06b531cfc7eddae3e588fff528))
- ~123 lines of tests, one case per chart type, cumulative setting and
edge case
([QueryResultChart.test.tsx](https://github.com/supabase/supabase/pull/50270/changes#diff-6e1c92ad725bac0324db4d079f3d0cd061b8f6e2aecdc21bcdc5969c90dc3c59))

## What is the current behavior?

Session replay is disabled in every environment, and no recordings
exist. This is about what a recording *would* contain if it were ever
switched on: charting a query result would put the customer's own column
names into it.

`ChartContainer` writes every chart config key into a `<style>` element
as `--color-<key>`. rrweb records `<style>` text verbatim:

```js
u = "STYLE" === parentTagName || void 0
h = "SCRIPT" === parentTagName || void 0
!u && !h && o && r && (o = maskTextFn ? maskTextFn(o, parent) : o.replace(/\S/g, "*"))
```

The `!u` guard means `maskTextFn` never sees stylesheet text. It is a
text node, so `maskAttributeFn` does not see it either. CSS written into
the DOM is a channel no masking hook reaches.

`QueryResultChart` keyed its config by the column names picked for the Y
axis, which come from the customer's own SQL results. With recording
enabled, a query charting a column named `customer_email` would produce
`--color-customer_email` in the captured DOM.

Linear [GROWTH-1229](https://linear.app/supabase/issue/GROWTH-1229).
#48818 masks the attribute channel. This channel is text, so that PR
does not reach it.

## What is the new behavior?

Y series are keyed by position (`series_0`, `series_1`), so no customer
string reaches the config keys.

The column name still goes through as `config[key].label`, which
`chart.tsx` renders into the tooltip and legend as text. Text nodes
outside `<style>` are masked by `maskReplayText`, so the name is safe
there and the chart stays readable.

The X column keeps its own name. Only config keys reach the `<style>`
and the X column is never one, so renaming it would buy nothing, and it
would cost the `timestamp` handling: `ChartBar` and `ChartLine` branch
on `xKey === 'timestamp'` to format tooltip dates and render the
date-range footer. Keeping the original name needs one guard, since an X
column literally named `series_0` would share a row key with the first Y
series. `xKeyFor` appends underscores until the two are distinct.

## Additional context

### Testing

Eleven tests. They assert the rendered `<style>` contains
`--color-series_0` and does not contain the column name, across both
chart types and both cumulative settings, plus the two-series case, the
`timestamp` column and the collision guard.

Three are verified to catch the defect they cover: the style-key
assertion fails against the unfixed component, the `timestamp` assertion
fails when the X key is pinned to a constant, and the `xKeyFor` cases
fail when the guard's body is removed.

`vitest run components/interfaces/Explorer` passes: 170 tests across 16
files.

The tooltip and legend path isn't asserted, because recharts doesn't
render either one at the 0x0 size jsdom gives the container. That the
label is what renders there comes from reading `chart.tsx`. It is
unverified at runtime.

### Remaining exposure

Every other `ChartContainer` caller passes literal keys
(`--color-error`, `--color-ok_count`), and `UnifiedLogs` filters a
static config by a fixed level set, so this was the only caller feeding
it customer strings.

`chart-bar.tsx:119-124` and `chart-line.tsx` still fall back to building
a config from whatever `dataKeys` they're given, so a future caller can
reintroduce this without touching `QueryResultChart`. A general guard
would have to live in `ChartContainer` or in the replay config.

CSSOM writes (`insertRule`, `replace`, `replaceSync`, adopted
stylesheets) also emit CSS outside both masking hooks. This PR does not
close that path.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **Bug Fixes**
- Improved query result charts to preserve the source column name used
for the X-axis.
- Prevented X-axis names from conflicting with generated series
identifiers.
- Ensured bar and line charts consistently bind data to the correct
X-axis and series.
- Preserved timestamp-based chart behavior, including the date-range
footer.
- Chart series styling now uses stable positional identifiers, ensuring
colors remain correctly assigned across configured series.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-14 09:48:47 -07:00