mirror of
https://github.com/supabase/supabase.git
synced 2026-10-10 03:45:06 +03:00
53e0e57ffee0afbcbc3a6883d00a9aed57f12e7d
39030
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
53e0e57ffe |
fix(storage): keep the preview panel's URL button and row handles as they were
The redesign renamed the panel's "Get URL" button to "Copy URL" while the row context menu kept "Get URL", leaving one action with two names, and gave the panel's file name a `title` — the attribute the explorer rows use as their handle, so `getByTitle` matched two elements once a preview was open. Also snap five off-token sizes to the scale the ratchet enforces, and point the E2E delete helper at the confirmation's real label now that it says what it does instead of ConfirmationModal's "Submit" default. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
183d5f2114 |
fix(storage): say the version matched the policy and will be deleted
Leads with what happened and that it is permanent, then bounds the wait. The previous wording blamed a missing schedule; the real reason there is no exact timestamp is that the cleanup spans several systems. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
fdd935c05f |
fix(storage): say cleanup can take up to 24 hours
There is no computable expiry timestamp: cleanup runs at no fixed moment and removal can lag by a day, so the tooltip says so rather than implying the next pass is imminent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
88f2609670 |
feat(storage): say a version is queued to expire, not expiring now
"Expiring now" claimed a moment that does not exist: cleanup is a periodic pass, so a version that has met the policy stays listed until it runs. The tooltip says why, within a max width. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
42a0ced1de |
fix(storage): refresh the row after restoring a version
Restoring a noncurrent version invalidated the version list but left the explorer row showing the old size, type and modified date, since the live listing is the explorer's own state rather than a React Query cache. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
ffc1ab56e6 |
refactor(storage): trim comments to one line where they earn their place
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
39f0406192 |
fix(storage): preview a version's own bytes, not the current ones
The version history rendered a generic mime-type icon per row, and the compare widget put that same icon on both sides — so every entry for a file looked identical and the comparison showed nothing to compare. The sign and public-url endpoints already accept `options.versionId`; nothing asked for it. `useFetchFileUrlQuery` now takes a `versionId` and keys on it, and the preview rendering moves out of `PreviewPane` into a `FilePreview` component both the pane and the compare widget use, so a version preview cannot silently fall back to the current bytes. Image rows in the history list render their own thumbnail under 5MB; larger files and other mime types keep the icon rather than pull a whole object down for a 28px box. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
e2cc696922 |
feat(storage): offer Archive and Delete permanently from the row menu
The file preview panel already splits the two on a versioned bucket, but the explorer's own row menu still offered a single "Delete" — which archives there, without saying so. The row menu now reads "Archive" on a versioned bucket and gains a "Delete permanently" entry beside it. `ConfirmPurgeModal` is mounted once by the explorer and driven by `itemToPurge` on the store, the same shape the row delete already uses. The preview panel routes its own permanent delete through it too, so the confirmation copy exists in one place rather than two. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
0b8ef6dad2 |
feat(storage): drive version history off the real endpoints
The preview panel now addresses versions by the object's full path, which is what the list, move and delete endpoints take, rather than by the leaf name the explorer renders. `VersionHistory` keeps `objectName` for copy and takes `path` separately. Expiry countdowns read the bucket's stored lifecycle policy instead of an empty placeholder, so a row's fate reflects the policy that governs it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3euXsz25sTybsGTcxCFfn |
||
|
|
0cd08c6b1a |
fix(storage): tell the truth in the empty version history
The empty state read "Overwriting this file will retain a recoverable copy here" regardless of whether the bucket was actually versioned. Since `getBucketVersioningState` reports `disabled` for every bucket until the API exposes the field, that promise was showing on every file in every bucket. Splits it: `disabled` now says versioning is off and points at the bucket settings; `enabled`/`suspended` keep the original copy. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
89e946acc2 | improve comments | ||
|
|
60d8c45f8e |
refactor(storage): drop the unreachable cap-only lifecycle branch
Follows the same change in the version-fate helper: a version cap always arrives
alongside an expiration age, so the policy summary only has three shapes to
describe (age alone, or age plus cap under either operator). Removes the
cap-only sentence and the "no age limit" chip, and `daysRemaining` on
`expires-on-next-upload` no longer needs an undefined guard.
Also adds the explicit `tabIndex={0}` that `supabase/require-explicit-tabindex`
wants on the four raw buttons in this feature. These were lint *errors*, not
warnings, so the ratchet never surfaced them.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
28b78001cb |
refactor(storage): say "retained" rather than "kept" for versions
Completes the rename in the version history rows, the lifecycle policy summary, and the delete confirmation copy. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
55fc610c2e |
feat(storage): add version history to the file preview panel
Rebuilds the file preview panel around object versioning: a collapsible Versions section listing every version with its removal outlook, an inline compare-and-restore widget, and delete actions that say what they actually do on a versioned bucket. - `VersionHistory` + `VersionHistoryPolicyRow` + `VersionThumbnail` — the version list, the inline lifecycle policy summary, and the row glyph - `VersionCompareWidget` — takes over the top of the panel when a noncurrent version is selected, so restoring is a visible comparison, not a modal - `PreviewSection` — the collapsible section wrapper - `PreviewPane` — new panel chrome, viewport-clamped thumbnail, and an Archive / Delete permanently split button on versioned buckets - `ConfirmDeleteModal` — on a versioned bucket a delete is a soft delete, so the copy no longer claims it cannot be undone Delete markers are surfaced as their own row type. They are the empty placeholders S3 writes on a soft delete, and they can outlive the delete (delete → upload → delete → restore leaves one mid-history), so a live file's history can contain them. There is nothing to preview or restore, so the row is non-interactive, dimmed, labelled "Delete marker", and its only action is removing the marker itself. Version data comes from the stubbed query added in the previous PR, so the Versions section renders its empty state until the Storage API lands. Fixes carried over from the prototype rather than ported: - Version rows were a clickable `<li>` whose `onKeyDown` passed a function reference instead of calling it, so keyboard activation did nothing. They are real `<button>`s now, which fixes activation and a11y together. - The policy summary put a `<Button>` inside tooltip content, unreachable by pointer or keyboard — now a `HoverCard`. - Permanent delete fired a bare `toast.success` with no mutation behind it. - Dropped the download and "Get version URL" menu items, which were toast stubs. - Deduplicated a double `filter` over versions and memoized the fate map. Also re-syncs `selectedBucket` in the explorer store when the bucket query refetches. It was only ever seeded once, so editing a bucket left consumers reading stale metadata — which is how Copy URL could sign a URL for the wrong visibility after a public/private toggle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
a7cf044118 |
feat(telemetry): capture ChatGPT Ads oppref click id (GROWTH-1278) (#51397)
## Problem ChatGPT Ads appends an `oppref` click id to landing URLs. We don't read it, so ChatGPT ad signups show up in PostHog with no click id and the first-referrer cookie doesn't treat the visit as paid. GROWTH-1278 ## Solution - Add `oppref` to the first-touch click ids sent with PostHog events (`telemetry.tsx`) - Add `oppref` to `CLICK_ID_KEYS` in `first-referrer-cookie.ts`, so it is stored in `_sb_first_referrer` and counts as a paid signal Conversion reporting to OpenAI itself goes through GTM, so it isn't part of this PR. ## Review instructions 1. Run `pnpm exec vitest run first-referrer-cookie` in `packages/common`. The `hasPaidSignals` test now covers `oppref`. 2. On the preview, load any page with `?oppref=test` and check the first-touch event in PostHog carries `oppref`. ## Checklist Check all before review: - [ ] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) - [ ] If I wrote a new docs topic or edited an existing topic, I used the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs [style guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide) Co-authored-by: Joshen Lim <joshenlimek@gmail.com> |
||
|
|
dbfa35ddb3 |
fix(studio): remove unsupported log drain form variants (#51449)
## Problem The log drain form still includes Postgres, ClickHouse, and BigQuery placeholder variants even though the dashboard does not offer these destinations. Production Platform API create/update types now exclude them, causing Studio type errors when the API declarations are regenerated. ## Fix Remove the unused variants from the form and submission schemas. Accept the broader response type for incoming defaults, resolve defaults through the selectable destination list, and use the form schema type for the selector. ## How to test - Run `pnpm --filter studio typecheck` with committed API types and with types generated from production. Both should pass. - Run Prettier and ESLint on `LogDrainDestinationSheetForm.tsx`. - Open project or organization audit log drain settings and add a supported destination. Available destinations remain unchanged. Validation: Studio typecheck passes with both committed API types and freshly generated production API types. Prettier passes; ESLint reports only existing warnings. Generated declarations are not included in this PR. |
||
|
|
514938f2a6 |
Revert "chore(www): update Subprocessor List to October 8, 2026 (#51445)" (#51448)
<!-- claude-slack-attribution --> _Requested by **Ali Waseem, Nicole Kramer** · [Slack thread](https://supabase.slack.com/archives/C0161K73J1J/p1791467710430139)_ ## Problem Before: the Subprocessor List page (`/legal/customer-resources/subprocessor-list`) links to the "Updated October 8, 2026" PDF, added in #51445. ## Solution After: the page links to the "Updated June 1, 2026" PDF again, until a page listing all historical lists is built. How: reverts #51445. Removes `October-8-2026.pdf` from `apps/www/public/legal/subprocessor-list/` and restores the `CURRENT_PDF` constant in `apps/www/pages/legal/customer-resources/subprocessor-list.tsx` to `June-1-2026.pdf` / `June 1, 2026`. `June-1-2026.pdf` was never removed, so it is still in place. This is reverted pending a different page structure. ## Review instructions 1. Open the preview of `/legal/customer-resources/subprocessor-list`. 2. Confirm the button reads "Subprocessor List - Updated June 1, 2026" and downloads the June 1, 2026 PDF. ## Checklist - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) - [ ] If I wrote a new docs topic or edited an existing topic, I used the `/write-the-docs` or `/edit-the-docs` skill (not applicable) 🤖 Generated with [Claude Code](https://claude.ai/code) https://claude.ai/code/session_01HVnxEAvXusb7JCGthHfMW7 --- _Generated by [Claude Code](https://claude.ai/code/session_01HVnxEAvXusb7JCGthHfMW7)_ Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
a259302f36 |
chore(www): update Subprocessor List to October 8, 2026 (#51445)
<!-- claude-slack-attribution --> _Requested by **Sofia Calado** · [Slack thread](https://supabase.slack.com/archives/C0161K73J1J/p1791467710430139)_ ## Problem Before: the Subprocessor List page (`/legal/customer-resources/subprocessor-list`) links to the "Updated June 1, 2026" PDF. ## Solution After: the page links to the new "Updated October 8, 2026" PDF. How: added `October-8-2026.pdf` to `apps/www/public/legal/subprocessor-list/` and updated the single `CURRENT_PDF` constant (`file` and `displayDate`) in `apps/www/pages/legal/customer-resources/subprocessor-list.tsx`. Old PDF: `June-1-2026.pdf` is kept in place so any existing links to it keep working. The directory had no history of removing old files, so I left it alone; it can be deleted in a follow-up if preferred. ## Review instructions 1. Open the preview of `/legal/customer-resources/subprocessor-list`. 2. Confirm the button reads "Subprocessor List - Updated October 8, 2026" and downloads the new PDF (header "As of October 8, 2026"). ## Checklist - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) - [ ] If I wrote a new docs topic or edited an existing topic, I used the `/write-the-docs` or `/edit-the-docs` skill (not applicable, no docs change) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01HVnxEAvXusb7JCGthHfMW7 --- _Generated by [Claude Code](https://claude.ai/code/session_01HVnxEAvXusb7JCGthHfMW7)_ Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
690ef5e7f7 |
feat(studio): scoped oauth apps, admins can see an app grants (#50979)
## Problem Admins need to see the grants associated to an approved OAuth application that uses scoped tokens. ## Solution - Add a menu to the org settings oauth approved apps rows to see the grant list - Update the react query hook to use infinite query for the grant list <img width="1149" height="356" alt="image" src="https://github.com/user-attachments/assets/2e6cfc76-5584-4447-aa19-a0bf103e2218" /> <img width="429" height="395" alt="image" src="https://github.com/user-attachments/assets/dd811d33-2c0a-46df-b9e9-3cbf8ad2fa7f" /> <img width="434" height="267" alt="image" src="https://github.com/user-attachments/assets/108905ba-4dcb-4dca-abe2-1a4e1fc3dbd2" /> ## Review instructions In Org Settings/OAuth apps, you should see a menu button for each app that contains a _View grants_ item. Clicking this item should open a dialog with the grants --------- Co-authored-by: kemal <hello@kemal.earth> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
ff98ac6452 |
chore(www) - fix redirects with 404 target destinations (#51413)
## Problem A subset of redirects were sending folks over to 404's via incorrect / outdated destinations. ## Solution Updates redirect targets to be accurate. ## Preview links TBD (though only the ones attached to the www app itself will be testable here). |
||
|
|
18080d88f7 |
Joshenlim/fe 4512 make GitHub connection setup obvious on empty branching page (#51393)
## Context Adds an empty state for the branch management page, if no preview branches have yet to be created (overview wont be shown) - mainly visual changes here. The main intention here is to surface the GH connection setup a bit more (otherwise the only CTA for that is in the side nav which is easily missed + its not clear up front what the benefit of the GH connection is in the context of branching) This is how it looked like before for reference: <img width="1346" height="956" alt="image" src="https://github.com/user-attachments/assets/776ce3f4-e12b-42e4-8e90-0d5ca15dc58f" /> And this is what I'm thinking for the empty state: <img width="1037" height="431" alt="image" src="https://github.com/user-attachments/assets/d3a8871e-74d2-499a-b317-f739ed925668" /> GH connection will flip its badge and hide the CTA if there already is a GH connection <img width="1038" height="443" alt="image" src="https://github.com/user-attachments/assets/4bf2d34d-6c74-4206-b83c-38ba84b99fb3" /> |
||
|
|
536fbd5470 |
fix: make auto rls SQL Multigres-compatible (#51428)
Part of resolving [INC-868](https://supabase.slack.com/archives/C0C8EBVUX2L/p1791443825740829?thread_ts=1791411302.921479&cid=C0C8EBVUX2L) Auto RLS SQL isn't Multigres-compatible since it uses `EXECUTE` with a freeform `%s` parameter Tested locally |
||
|
|
12ab771e86 |
feat(studio): authorized apps table in org settings (#50529)
<img width="1150" height="669" alt="image" src="https://github.com/user-attachments/assets/0b324577-bed5-4272-a7e0-f4444a0c1230" /> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com> |
||
|
|
af3e397e7f | feat(credit-codes): show that credit codes were reduced by partner deals (#51173) | ||
|
|
78dc739901 |
fix(studio): show support inline and honour AlertError layouts (#51377)
## Problem AlertError forces a vertical layout whenever additional actions are supplied, even when the caller explicitly requests horizontal or responsive layout. Stripe Sync Engine's uninstall error is one affected call site, the other was Pipelines as demoed in #51311. ## Solution Honour an explicit layout. Preserve the existing defaults: vertical with additional actions, responsive otherwise. Replace the standalone Contact support action with an InlineLink in the contact support prose, preserving support form context and breadcrumb capture. Keep custom actions such as Retry. If instructions are hidden or custom prose omits contact support, retain a separate inline support link. With `hideContactSupport`, show no support link and shorten the default instructions to “Try refreshing your browser.” Custom descriptions remain unchanged. The local Pipelines configuration error explicitly hides support. Add the explicit responsive layout at the Pipelines call site. | Before | After | | --- | --- | | <img width="914" height="426" alt="CleanShot 2026-10-07 at 17 51 20@2x" src="https://github.com/user-attachments/assets/6cbddfee-97f5-4a7a-bafa-7b5dfd6ab8bf" /> | <img width="916" height="422" alt="CleanShot 2026-10-07 at 18 26 06@2x" src="https://github.com/user-attachments/assets/a21952a6-1c1a-437c-af73-c5736f33fd98" /> | | <img width="1566" height="384" alt="CleanShot 2026-10-07 at 18 28 07@2x" src="https://github.com/user-attachments/assets/bdc2a043-421f-4c22-9bd3-37859c6e85c7" /> | <img width="1568" height="308" alt="CleanShot 2026-10-07 at 18 26 58@2x" src="https://github.com/user-attachments/assets/da0f2c6a-6254-4196-944b-5665e87b3c3c" /> | ## Review instructions 1. In a fresh local test project with no existing `stripe` schema, run this in SQL Editor: ```sql begin; create schema stripe; comment on schema stripe is '{"status":"uninstall error","errorMessage":"Local layout test: uninstallation failed"}'; commit; ``` 2. Open **Integrations → Stripe Sync Engine → Overview** and reload. Check **Failed to uninstall Stripe Sync Engine** at wide and narrow widths, including **Retry uninstallation** and the inline **contact support** link. Do not click Retry: it invokes the real uninstall operation. 3. Remove the empty fixture with `drop schema stripe restrict;`. 4. Block the Pipelines source-status request and resize the page: Retry uses the responsive layout. 5. AlertError callers without an explicit layout should retain their existing presentation. Confirm default and custom contact support prose use an inline link, with no standalone support action. Hidden instructions and custom prose without contact support retain an inline fallback. With `hideContactSupport`, the default prose is “Try refreshing your browser.” and no support link appears; custom descriptions remain unchanged. 6. Automated regression coverage checks that an explicit responsive layout survives additional actions, and that hiding support removes the default support wording while preserving custom descriptions. --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com> |
||
|
|
26c838a433 |
Joshenlim/fe 4590 studio sql export can silently swap values for numeric (#51382)
## Context Resolves https://github.com/supabase/supabase/issues/51330 Odd bug on the Table Editor where "Copy as SQL" CTA would misalign column names to values if the columns had numerical like names such as `2024` for example. Also added an unrelated fix for "Copy as JSON": - Was adding an `idx` column to the output even if the table didn't have (was a react data grid internal detail) - Column name ordering didn't match the table ## To reproduce: 1. Create and populate a table: ``` create table public.yearly_totals (id bigint, "2024" bigint, "2023" bigint); insert into public.yearly_totals values (7, 99, 42); ``` 2. Select the row in the Table Editor, then "Copy as SQL" -> The output will turn out to be ```INSERT INTO public.yearly_totals (id, "2024", "2023") VALUES (42, 99, 7);``` instead of ```INSERT INTO public.yearly_totals (id, "2024", "2023") VALUES (7, 99,42);``` ## To test - [ ] Verify that the Copy to SQL output matches the intended as per the set up above |
||
|
|
33c5f91e6f | chore(docs): Add Brad Deam to humans.txt (#51418) | ||
|
|
6c829b32da |
fix(studio): enable Pipelines before opening creation (#51311)
## Problem Add pipeline opens the creation sheet before users enable Pipelines. A pending or failed source lookup also lets creation open with an unknown enablement state. ## Solution Show the existing enablement dialog first when required, then open creation after successful enablement. Cancellation and failed enablement keep creation closed; enabling through the page menu does not open creation. Disable both Add pipeline buttons and their keyboard shortcut until the source lookup succeeds. Failed lookups show an error with Retry, including the local replication configuration message. Analytics Bucket keeps its existing creation path. | Before | After | | --- | --- | | <img width="1275" height="919" alt="Pipelines Database Shears Toolshed Supabase" src="https://github.com/user-attachments/assets/cf328732-4342-4758-bde2-98b393341d6a" /> | _No longer in sheet; dialog is shown conditionally before sheet._ | | <img width="1275" height="919" alt="Pipelines Database Shears Toolshed Supabase" src="https://github.com/user-attachments/assets/f593e271-d29c-4955-8849-0bb64946d4cc" /> | <img width="1275" height="919" alt="Pipelines Database Shears Toolshed Supabase" src="https://github.com/user-attachments/assets/3257d391-b892-44df-85d1-5a2108072312" />| | _“Enable Pipelines”_ | _“Enable”_ | | After | | --- | | <img width="1275" height="919" alt="Pipelines Database Shears Toolshed Supabase" src="https://github.com/user-attachments/assets/b11770a1-4785-49ee-950d-d821892b3245" /> | | _Loading_ | | <img width="1275" height="919" alt="Pipelines Database Shears Toolshed Supabase" src="https://github.com/user-attachments/assets/710f82be-ca6f-4337-a5ce-b65f9d7f6a32" /> | | _Lookup failed_ | | <img width="1275" height="919" alt="Pipelines Database Shears Toolshed Supabase" src="https://github.com/user-attachments/assets/68486ca8-37e8-4b27-89ae-8004f159c38a" /> | | _Plan-access loading, throttled_ | ## Review instructions Use a project with Pipelines access and a working replication API (which should work on [deploy preview](https://studio-staging-git-dnywh-fixpipeline-enable-create-supabase.vercel.app/)). Test the PR preview or locally ([instructions](https://app.notion.com/p/supabase/Danny-s-Local-ETL-Pipelines-Setup-3b25004b775f8058a108f8f67fc813e9?source=copy_link)). In DevTools Network, enable **Disable cache** before each reload. Analytics Bucket intentionally bypasses the source-status guard. 1. **Loading:** select **Slow 3G**, reload, and watch the request ending in `/replication/<ref>/sources`. While it is pending, both **Add pipeline** buttons must be disabled and **Shift+N** must open nothing. Both buttons replace the plus with a loading spinner and have no loading tooltip. Restore **No throttling** afterwards. 2. **Lookup failed:** right-click that source request and choose **Block request URL**, then reload. After retries finish, expect **Failed to retrieve pipeline enablement status** with **Retry**, disabled Add buttons whose tooltip matches the error title, and no sheet/dialog from **Shift+N**. An unconfigured local replication API instead shows **Replication unavailable locally**. Unblock the request before clicking **Retry**. 3. **Lookup succeeded:** on a disposable project with Pipelines disabled, successful Retry restores Add pipeline. Clicking it opens **Enable Pipelines**. Cancel stays on the list; **Enable** opens the sheet after successful enablement. On an already enabled project, Add pipeline opens the sheet directly. Enabling through the page's three-dot menu stays on the list. Analytics Bucket opens its sheet without ETL enablement. 4. **Plan-access loading is separate:** in Chrome 145 or newer, find `/organizations/<slug>/entitlements` in Network, right-click it and choose **Throttle request**. In the **Request conditions** drawer, select Slow 3G for that request only, leaving global throttling off. Reload on a Pro organisation with Pipelines disabled and open Add pipeline after the source lookup succeeds. While entitlements remain pending, expect body shimmers, the accessible “Checking Pipelines access…” status, a disabled loading **Enable** button, and no upgrade prompt. Remove the request condition afterwards. If your DevTools lacks per-request throttling, use the component tests for deterministic coverage. |
||
|
|
5056af35e7 |
chore(www): add on-demand webinar with AWS on securing and scaling vibe-coded apps (#51416)
## 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? Content: new on-demand webinar event page. ## What is the current behavior? There is no event page for the AWS AI-Native Dev Stack webinar. ## What is the new behavior? Adds an on-demand event, "Secure and scale vibe-coded applications with Supabase and AWS", in the same format as the Datadog on-demand webinar: - `main_cta` ("Watch the recording") links to the recording hosted by The Register - Speakers: Nick Littman (Supabase) and Mrinali Umashankar (AWS) - Adds Mrinali Umashankar and her avatar to `authors.json` and `public/images/blog/avatars` - Listed under the On-demand filter on `/events` ## Additional context Event date is set to Sept 9, 2026. Pre-flight checks (per CONTRIBUTING.md): Prettier passes on the changed files, and `pnpm build --filter=www` completes successfully locally. |
||
|
|
7776b1f7ee |
docs(www): add Data Residency and Transfers FAQ legal page and Privacy Resources hub section (#51318)
<!-- ccr-slack-attribution --> _Requested by **Sofia Calado** · [Slack thread](https://supabase.slack.com/archives/C0161K73J1J/p1791273150504749?thread_ts=1791273150.504749&cid=C0161K73J1J)_ **Before:** The Data Residency and Transfers FAQ only existed as a PDF. The Legal Hub (`/legal`) listed the Data Processing Addendum and the Subprocessor List under "Customer Legal Resources", with no privacy-specific grouping. **After:** The FAQ is a native, indexable page at `/legal/privacy-resources/data-residency-and-transfers-faq`. The Legal Hub has a new "Privacy Resources" section with the Data Processing Addendum, the Subprocessor List and the FAQ. The DPA and Subprocessor List URLs are unchanged. This publishes the FAQ as a web page and groups it with the other privacy documents in the Legal Hub. ## Problem The FAQ needs to be discoverable on supabase.com (including search) and linked from the Legal Hub next to the DPA and Subprocessor List. ## Solution How: the page mirrors the DPA shell (`DefaultLayout` > `NextSeo` > `PageHeader` with `PageBreadcrumb` > `MDXProvider` > `LegalDocVersions`) with a single `v1` entry. The body is `data/legal/privacy-resources/data-residency-and-transfers-faq/v1.mdx`, transcribed verbatim from the source PDF (17 questions in 9 sections), with one correction confirmed by the requester: the marketplace Note names "Supabase, Inc.", and the "plan documentation" link points to `/docs/guides/platform/backups`. The Transfer Impact Assessment has no direct link, so it and the Trust Center link go to `https://trust.supabase.io`, as confirmed by the requester. The version date reads "October 6, 2026", per the requester (the source PDF gave only the month), and the closing "Last updated / Owner" line from the PDF is dropped. Further edits made at the requester's direction: the Usage Information bullet in the retention answer no longer states a log purge period, and the Usage Information category in the data-location answer now says "processors". PDF hyperlinks are mapped to real routes. The hub gets a `privacy-resources` section, and the DPA and Subprocessor List breadcrumbs now point to it (text and anchor only). The sitemap is generated from `pages/**/*.tsx`, so the new route is included without changes. ## Review instructions 1. Open `/legal` and check the "Privacy Resources" section lists the three documents, and "Customer Legal Resources" still lists Terms of Service, Support Policy and Service Level Agreement. 2. Open `/legal/privacy-resources/data-residency-and-transfers-faq` and compare the text with the source PDF. 3. Click through the links in the page, and the breadcrumbs on the DPA and Subprocessor List pages. ## Open questions for Legal None remaining. The requester's edits are applied: the closing "Last updated" line is removed, the ISO 27001 / SOC 2 link goes to `/security`, the "Legal Hub" link in the subprocessor question goes to `/legal`, and the meta description wording is confirmed. ## Checks - `pnpm install --filter www...` worked. Prettier check passes on the touched files, MDX compiles, and `next dev` renders both `/legal` and the new page (200, indexable, canonical set). - Full `tsc`/lint/`next build` were not run as CI-equivalent. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_012JHSu7iLpQ3XPfmfQzFraw --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
d72211556b |
feat(studio): link overview Machine size card to Infrastructure settings (#51402)
## Problem
The project overview shows the project's compute size in a card labeled
"Compute", but the card is not clickable. Compute changes are managed on
Infrastructure settings, so users have to find that page on their own.
The adjacent cards (GitHub, Recent branch, Last migration, Last backup)
already link to where you manage them.
## Solution
- Rename the card label from "Compute" to "Machine size" and pass
`href={getInfrastructurePath(ref)}` to `SingleStat`. That renders the
same `Link` wrapper as the adjacent cards, so it gets the same link
semantics, keyboard focus and hover style. The value (compute badge or
"Unknown", plus the High Availability badge) is unchanged.
- Add `onClick={(e) => e.stopPropagation()}` to the
`HighAvailabilityBadge` hover card content. This is the same pattern
`ComputeBadgeWrapper` already uses. The hover card is portaled, but
React still bubbles its clicks to the new card link. Without this, the
link's `onClick` would intercept clicks inside the HA hover card.
Clicking "Read more" would then go to Infrastructure instead of opening
the docs in a new tab.
Out of scope: "Compute" labels elsewhere, the Infrastructure page and
compute provisioning behavior.
Notes:
- The compute badge's hover card trigger already calls `stopPropagation`
on click, because it also sits inside clickable project cards and table
rows. When you click the badge itself, the browser still follows the
native anchor to Infrastructure settings, but it does a full page load
instead of a client-side navigation. This PR leaves that shared
component unchanged.
- While the project is resizing, the overview is replaced by the
resizing state, so the card is not shown then. Settings routes stay
reachable while a project is building, so the link doesn't bounce users
back home.
- No new component test: rendering `ActivityStats` needs mocks for about
eight queries, including `ServiceStatus`. The change only sets an `href`
on an existing component, so a browser check is a better fit.
## Review instructions
1. Open a platform project's overview (`/project/<ref>`).
2. The card next to Status reads "Machine size" and still shows the
compute badge (and the HA badge on HA projects).
3. Click the card, or Tab to it and press Enter. You land on
`/project/<ref>/settings/infrastructure`.
4. Hover the compute badge: its hover card still opens, and "Upgrade
compute" still goes to Infrastructure.
5. On an HA project, hover the High Availability badge and click "Read
more". The docs open in a new tab and the page does not navigate.
6. GitHub, Recent branch, Last migration and Last backup keep their
labels and destinations.
Checks: `tsc --noEmit` for Studio (no new errors; one unrelated error in
`packages/ui-patterns/.../InstructionBlocks.tsx` was already there),
`eslint` on the touched files (no new warnings), Prettier check, `vitest
components/interfaces/ProjectHome` (34 passed).
## Checklist
- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [ ] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs
[style
guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide)
---------
Co-authored-by: supabase-vercel-tedd[bot] <336548405+supabase-vercel-tedd[bot]@users.noreply.github.com>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
|
||
|
|
2d0bd7af69 |
feat(storage): add object versions data layer (#49207)
| # | Branch | Base | | - | ------ | ---- | | 1 | `feat/storage-versioning-private-alpha` — merged | `master` | | 2 | `feat/storage-versioning/002-bucket-form-fields` | `master` | | 3 | `feat/storage-versioning/003-bucket-modals` | 2 | | 4 | `feat/storage-versioning/004-object-versions-data` ◀ | 3 | | 5 | `feat/storage-versioning/005-file-preview-versions` | 4 | | 6 | `feat/storage-versioning/006-billing-storage-retention` | 5 | | 7 | `feat/storage-versioning/007-archived-objects-data` | 6 | | 8 | `feat/storage-versioning/008-archived-rows` | 7 | | 9 | `feat/storage-versioning/009-archived-preview-pane` | 8 | | 10 | `feat/storage-versioning/010-replace-file` | 9 | ## [4/10] Storage object versioning: object versions data layer **Base:** `feat/storage-versioning/003-bucket-modals` (PR 3) ### This PR The query and mutation hooks for the version history UI, written to `queryOptions` using the real Storage endpoints. - `object-versions-query.ts` — the version list, plus `ObjectVersion` and `LifecyclePolicy` - `object-version-restore-mutation.ts` — promote a noncurrent version to current - `object-version-delete-mutation.ts` — remove one specific version - `object-purge-mutation.ts` — delete an object and every version, bypassing versioning - `VersionHistory.utils.ts` — `computeVersionFate`, the pure rule deciding what removal outlook each version row shows - `BroomSparklesIcon.tsx` — inline SVG for a glyph absent from lucide-react 0.436 Easier to test directly from next PR in the stack #49208 which wires the queries to the real file preview panel ui. --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
5c68e24faf |
fix(docs): keep collapsed sidebar group links in the server HTML (#51373)
Part of [DOCS-1432](https://linear.app/supabase/issue/DOCS-1432/discovery-gather-information-and-data) ## Problem While doing Discovery for Information Architecture, I found that my agents were taking 10+ clicks to find a page. This was _really_ bad. But it turns out it's an accessibility issue; the agent can't _see_ any nested subnav item. Allowing the dom to access the subnav without toggling an accordion allows an agent to freely navigate, completely resolving some of my failing evals. ## Solution - **Render a hidden list of each group's links.** A `<ul hidden>` next to each group holds its links, nested groups included, so they are in the HTML. The accordion is unchanged, so the sidebar looks and animates the same as production. - Checked for accessibility. ## Manual testing 1. Open the [Platform hub on the deploy preview](https://docs-git-docs-nav-render-collapsed-links-supabase.vercel.app/docs/guides/platform). In the sidebar, **Single Sign-On** and **Multi-factor Authentication** are collapsed. 2. Run `curl -s https://docs-git-docs-nav-render-collapsed-links-supabase.vercel.app/docs/guides/platform | grep -o 'href="/docs/guides/platform/sso"'`. It prints the link. The same command against supabase.com prints nothing. 3. Click **Single Sign-On**. It opens and shows its guides, including SSO with Google Workspace. 4. Click **Single Sign-On** again. It closes. Notice animation is intact. |
||
|
|
329b0a0156 |
fix(studio): animation gradient on log drains empty state (#51403)
## Problem Animation had values that became deprecated after colour migration. ## Solution Updated to use the same background colour as everywhere else. To test, on a free organization navigate to Settings > Log Drains. | Before | After | |--------|--------| | <img width="764" height="356" alt="Screenshot 2026-10-07 at 18 20 21" src="https://github.com/user-attachments/assets/eb07c4fa-e089-4558-83fe-01ff189eeae4" /> | <img width="760" height="342" alt="Screenshot 2026-10-07 at 18 24 06" src="https://github.com/user-attachments/assets/dc7b3998-df1c-4df0-ae15-e23286787cf4" /> | |
||
|
|
a8b2f23091 |
fix(studio): restore deployment update metadata (#51048)
Deployment update checks now receive a timestamp from GitHub’s documented commit API instead of silently falling back to `unknown` when its website response changes. Valid deployment metadata is cached for ten minutes; development and failed lookups are uncached so they can recover. **Changed:** - Validate and normalize the committer date in the shared Next/TanStack handler, preserving the existing response shape and `unknown` fallback. - Exclude only the exact deployment-metadata endpoint from TanStack’s private API cache default; authenticated APIs and server functions retain it. - Keep the client update query unpinned and its existing toast threshold unchanged. **Added:** - Shared-handler tests through both Next and the TanStack adapter for dates, malformed payloads, upstream failures, and recovery. - Tests using the installed Vercel route compiler for root and `/dashboard` cache rules, security headers, and empty Next configuration. ## To test - On the TanStack preview, request `/dashboard/api/get-deployment-commit`; compare its SHA and UTC timestamp with the deployed commit’s GitHub committer date. - Repeat the request to check CDN caching. Vercel consumes `s-maxage`, so use cache-hit/age evidence as well as client-visible headers. - Confirm another API route and a server-function path retain `private, no-store`. - Open an existing project, reload it while clean, and inspect the untouched support form for metadata-related errors. Validation: 60 focused tests, Studio typecheck, scoped ESLint, formatting, knip, and both framework production builds passed. Live unauthenticated GitHub lookup with the configured API version returned the expected committer date. Full source lint ratchet also passed, excluding only generated build directories. Local TanStack browser checks passed for clean project/reload, general settings, untouched support form, and naturally emitted development metadata formatting; no errors or unexpected update toast appeared. The positive two-deployment toast and submitted support-version formatting were not exercised. Deployed native Next previews returned the exact commit SHA and expected UTC timestamp; repeated metadata requests produced CDN HIT responses (ages 26 and 100 seconds). Build logs establish that the staging preview also ran Next, so it does not validate TanStack edge header behavior. A separate preview-only redeployment with a deployment-scoped TanStack override was confirmed to run Vite. It returned the same correct SHA/timestamp, a repeat CDN cache HIT, and private, no-store on the neighboring UTC API. No project settings or production aliases were changed. Installed Vercel compiler tests cover the remaining root/base-path and server-function rules. No new environment variable, token, or dependency is required. Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |
||
|
|
8d08198cb4 |
fix(studio): preserve TanStack server source maps (#51051)
TanStack server maps now preserve original TypeScript locations through both Nitro build stages. Sentry can upload those maps before final server and public maps are removed; intermediate SSR maps remain available for composition. **Changed:** - Enable Nitro server maps with original source content and compose adjacent SSR maps through a build-only Vite loader scoped to the Nitro environment. - Keep intermediate maps until Nitro consumes them. Apply Sentry’s bundler plugin to client and final server outputs, preventing intermediate SSR IDs from overriding the final uploaded map ID. Remove final server maps after eligible uploads; skipped or unauthenticated uploads retain private maps. - Preserve the existing Sentry release, project, credentials, middleware, and separate Next configuration. **Added:** - Real two-stage Node and Vercel build regressions for original TypeScript positions, runtime debug-ID matching against the installed Sentry SDK, map cleanup timing, malformed maps, and loader boundaries. ## To test - Build an actual TanStack preview with the existing Sentry upload settings. Confirm client and final server uploads include maps, intermediate SSR maps remain available for composition, final/public maps are removed, and the deployed function remains within its size limit. - Inspect a public JavaScript asset's map URL; it should not expose a source map. - Build with uploads skipped or credentials absent; private server maps should remain, with no public maps. - Reload an existing project and navigate through general settings and an existing Edge Function without editing or submitting anything. - Before production rollout, confirm browser and server events resolve to useful original source locations in the intended Sentry project. Validation: 22 focused tests, Studio typecheck, scoped ESLint, formatting, knip, full source lint ratchet, and both framework production builds passed. Full-app artifact tracing resolves a compiled handler to its original TypeScript line with exact source content. The skipped-upload Vercel build contains zero public maps and no function symlinks. Local TanStack browser checks passed for project/reload, untouched general settings and support, and an existing function editor/reload; a final retest after the runtime-ID fix passed with no module or Sentry errors. A previously observed devtools support-lifecycle warning remains unattributed. An explicit TanStack preview of this commit reached READY: client and final Nitro uploads succeeded, with no intermediate SSR upload. A shell-referenced JavaScript asset returned 200 with immutable caching and its map URL returned 404. Upload reports still contain unmapped files; original app TypeScript mapping and runtime-ID association are established by build artifacts/fixtures, while real event deobfuscation remains rollout QA. Deployment acceptance confirms this preview fits its configured function limits; exact deployed size and post-upload server contents were not independently downloaded. No package patch, dependency, or new environment variable is required. Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |
||
|
|
ccb1c60166 | fix: show dialog to prevent restoring larger projects to nano compute (#51309) | ||
|
|
690d67e372 |
fix(studio): hash TanStack deployment pins in build cache (#51054)
Studio builds now hash `VERCEL_DEPLOYMENT_ID` because TanStack embeds it in server-function request pins. Cached output cannot retain an earlier deployment ID when redeploying the same commit. **Changed:** - Move the ID from `passThroughEnv` into `build.env`, keeping runtime pinning and Skew Protection settings intact. - Turbo-managed Next builds with a new ID also invalidate the Studio cache; upstream package caches remain reusable. ## To test - Run strict Turbo dry runs with two deployment IDs for each framework: Studio hashes should differ, an unchanged ID should remain stable, and upstream hashes should remain unchanged. - Build Next and TanStack. With skew protection enabled, confirm the TanStack client/server output includes the current deployment pin. - Reload an existing project and function editor and navigate through settings without edits. Validation: actual Turbo dry runs reproduced identical hashes before the fix and verified distinct/stable hashes afterward for both frameworks. Studio typecheck, full source lint ratchet, knip, formatting, and both production builds passed. Emitted TanStack client/server artifacts contain the synthetic validation ID and deployment header. Local TanStack checks passed for overview/reload, untouched settings plus Back, functions list, existing function source/reload, and final clean return; no console errors or backend changes. Cache-key and genuine server-function routing claims are separate from this UI coverage. No new environment variable, dependency, or package patch is required. Current Vercel app builds invoke the framework directly through the Studio dispatcher; this change applies when Studio builds run through Turbo. --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |
||
|
|
55c297655e |
fix(studio): keep project sidebar navigation accessible (#51055)
Project sidebars now expose enabled navigation on fixed-width pages, and the mobile project menu has an accessible dialog name. Fixed sidebar sizing and editor resize controls remain intact. **Changed:** - Remove the disabled state from the shared sidebar panel while retaining 256px fixed sizing, the disabled resize handle, and existing editor resize limits. - Add a screen-reader-only Project menu title inside the mobile project sheet without changing other sheets or their titles. **Added:** - Tests using the actual resizable wrappers for enabled navigation and handle semantics, and the actual mobile sheet for its accessible name through menu navigation. ## To test - Navigate through Database and Settings sidebar links with ordinary clicks and Tab/Enter. Enabled links should have no disabled ancestor. - Confirm fixed sidebars remain 256px wide, including an ordinary drag of their disabled handle. - In SQL Editor, verify keyboard resizing stays within 256–512px and collapse/expand still works; restore the original width and visibility without editing or executing anything. - Open the mobile project menu. Confirm its dialog name is Project menu, navigate through Tables, and close it without a missing-title warning. Restore the viewport. Validation: real regressions reproduce disabled navigation inheritance and the unnamed mobile dialog before their fixes. All 26 focused layout/menu/utility tests and source checks passed. Initial full browser checks passed normal mouse/keyboard navigation, fixed-handle drag resistance, editor resize limits, collapse/expand, and mobile navigation, with viewport/state restored and no backend writes. Both Next and TanStack production rebuilds passed. The focused mobile retest passed the linked Project menu title through sections, closing, navigation, and reopening with no new missing-title warnings, followed by desktop sidebar and editor controls; viewport, width, and visibility were restored. Unrelated development React mount/ref warnings remain separately recorded; native Next local browser and catalog data were not verified. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Project sidebar links remain available when sidebar resizing is turned off; the resize handle stays unavailable in that setting. * The mobile project menu retains the “Project menu” name as you navigate between sections. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |
||
|
|
46b7382d50 |
fix(studio): serve Deno declarations as TypeScript (#51057)
## Problem TanStack does not preserve Next's `text/typescript` content type for the public Deno declarations. This change restores MIME parity; Monaco already rendered before the fix. ## Solution Add the TypeScript header for `/deno/*.ts` at root and configured base-path URLs. Dynamic API and server-function responses keep their own content types, security headers and cache rules. Next retains its existing configuration. Tests use the installed Vercel routing compiler to cover both declarations, suffix boundaries, dynamic routes, security headers, the flags endpoint and the empty Next configuration. ## Review instructions 1. On a TanStack deployment, request `/deno/edge-runtime.d.ts` and `/deno/lib.deno.d.ts` at root and `/dashboard`. Expect 200, `text/typescript` and unchanged file contents. 2. Check missing `.ts.map`, `.tsx` and similar paths return 404 without the TypeScript override. API and server-function responses should retain their own content types. 3. Open an existing function editor and reload it without editing or deploying. Confirm the file tree and source still render. 4. Build Next and TanStack. Confirm Next retains its existing configuration. Validation: the routing compiler reproduces four declaration-header failures before the fix; all 30 content-type cases and 10 SPA route tests pass afterward. Typecheck, knip, the source lint ratchet, scoped lint, formatting and both production builds passed with uploads disabled. Built declarations are byte-identical to their public sources. Local TanStack checks passed the function list, existing source view, exact editor reload and clean project return without edits or backend writes. Native Next UI was not tested locally. The combined TanStack preview at QA commit `f35b3c42d8ba6a714299b148d797b09107a7a6fe` returned 200, `text/typescript`, nosniff and byte-identical contents for both declarations at root and `/dashboard`. Missing `.ts.map` and `.tsx` paths returned 404 without the override; neighboring dynamic API responses retained JSON content type and private caching. This preview evidence covers the combined original fixes, not the subsequent dependency upgrade. ## Checklist - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md). - [x] No docs content changed; docs authoring skills are not required. --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |
||
|
|
820ff0f2d2 |
fix(studio): handle invalid TanStack API request bodies (#51046)
Malformed JSON now returns `400 Invalid JSON` from the TanStack API
adapter instead of an unhandled 500. Empty JSON bodies and undecodable
cookies follow the existing Next parser behavior.
**Changed:**
- Handle JSON parsing failures before invoking the API handler, while
preserving body-read and downstream handler errors.
- Recognize exact JSON and JSON-LD media types, including case and
charset parameters.
- Keep raw cookie values when URI decoding fails.
**Added:**
- 43 adapter tests covering valid and invalid bodies, cookies, handler
isolation, response headers, streaming, and abort events.
## To test
- POST malformed JSON to `/api/parse-query` with `Content-Type:
application/json`; expect 400 with `Invalid JSON`. Repeat with JSON-LD.
- POST `{"sql":"select 1"}` to the same endpoint; expect 200. This
parses SQL without executing it against a database.
- Repeat the valid request with an undecodable cookie value; expect the
same successful result.
- Open an existing project and database settings; verify normal API
consumers remain usable.
Validation: 59 focused tests, 29 differential body cases plus malformed
cookies against installed Next parsers, Studio typecheck, lint ratchet,
scoped ESLint, formatting, knip, and both framework production builds
passed. Direct local HTTP checks passed for malformed, empty, valid, and
malformed-cookie requests. Next handlers, routes, environment files, and
dependencies are unchanged. Local TanStack browser checks passed for
signed-in project rendering, clean reload, and the untouched support
form. Database settings rendered its error state, but the banned-IP
service returned an upstream connection-timeout payload, so successful
list coverage remains unverified. Chrome blocked direct API-document
navigation; malformed-input behavior is covered by the separate HTTP and
parser checks.
The automatic staging preview ran native Next (confirmed from its build
output), providing an additional Next regression check: malformed JSON
and JSON-LD returned exact `400 Invalid JSON`; valid SQL parsing
returned 200; an undecodable cookie preserved the same valid response.
No SQL was executed. The local TanStack runtime and in-process adapter
checks passed; the combined TanStack deployment results follow.
The combined rollout preview (TanStack, QA commit
`f35b3c42d8ba6a714299b148d797b09107a7a6fe`) also passes deployed
malformed JSON/JSON-LD 400, valid SQL parsing 200, and
undecodable-cookie 200 with the same valid response. No SQL is executed
against a database.
---------
Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
|
||
|
|
6c150d26d9 |
docs(mgmt-api): clarify rate limits are per endpoint (#51379)
## Problem The Management API rate limits docs said limits are per user and per project or organization. They didn't say that each endpoint also has its own limit, or how requests without a project or organization, and tokens versus OAuth apps, are counted. The partial also had a typo, a repeated example, and a tracking-key sentence that listed endpoint as a scope. ## Solution Edits to `apps/docs/content/_partials/api_rate_limits.mdx`, in one commit per change type: 1. `docs(mgmt-api): clarify rate limits are per endpoint`: the content change. It adds the per-endpoint model, the user scope, the `POST /v1/projects` scoping, and who the limit applies to. 2. **Style**: fixes the `enpoint` typo and the table alignment, removes the repeated Project A/B paragraph and the `database/context` note that restated its table rows, unwraps hard-wrapped lines, and aligns bold labels and wording with the style guide. 3. **Structure**: moves "Rate limit response headers" after "Who the limit applies to", so the concept sections come before the reference sections. No headings were renamed, and no inbound anchors to them exist in `apps` or `packages`. 4. **Technical**: the tracking-key sentence now reads "scope (project or organization) and the endpoint". It previously listed endpoint as a scope, which contradicted the scope list. Not verified against the rate limiter, which isn't in this repo. A reviewer with access should confirm: - Requests without a project or organization count against the user. - `POST /v1/projects` is organization-scoped via `organization_slug`. - Personal access tokens share the user's limit, and OAuth apps share the app's limit. - The tracking-key wording in commit 4 is inferred from the page, not from code. ## Preview links | Site | Live | Preview | Search for | | ---- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------ | | Docs | [/docs/reference/api/introduction](https://supabase.com/docs/reference/api/introduction) | [/docs/reference/api/introduction](https://docs-git-docs-mgmt-api-rate-limits-per-endpoint-supabase.vercel.app/docs/reference/api/introduction) | `Who the limit applies to` | ## Review instructions 1. Open the live and preview links side by side and scroll to "Rate limits". 2. Check that the section order is: Standard rate limit, Rate limit scope, How rate limits are tracked, Who the limit applies to, Rate limit response headers, Endpoint exceptions, Best practices. 3. Check that the scope table and the endpoint exceptions tables render correctly. 4. Review commit by commit, since each commit is one change type. 5. If you can read the rate limiter code, check the unverified claims listed above. ## Checklist Check all before review: - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) - [x] If I wrote a new docs topic or edited an existing topic, I used the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs [style guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
|
|
dc4830c480 |
feat: update @supabase/*-js libraries to v2.117.3 (#51392)
This PR updates @supabase/*-js libraries to version 2.117.3. **Source**: supabase-js-stable-release **Changes**: - Updated @supabase/supabase-js to 2.117.3 - Updated @supabase/auth-js to 2.117.3 - Updated @supabase/realtime-js to 2.117.3 - Updated @supabase/postgest-js to 2.117.3 - Refreshed pnpm-lock.yaml --- ## Release Notes ## v2.117.3 ## 2.117.3 (2026-10-07) ### 🩹 Fixes - **deps:** bump next to patch RCE in realtime-js example ([#2733](https://github.com/supabase/supabase-js/pull/2733)) - **functions:** send a Blob or File with its own content type ([#2714](https://github.com/supabase/supabase-js/pull/2714)) - **postgrest:** treat TimeoutError as an abort in retry guard ([#2732](https://github.com/supabase/supabase-js/pull/2732)) - **storage:** send multipart fields before files ([#2736](https://github.com/supabase/supabase-js/pull/2736)) ### ❤️ Thank You - Bruno Gale @fresh55 - Ferhat Elmas - Katerina Skroumpelou @mandarini ## v2.117.2 ## 2.117.2 (2026-09-25) ### 🩹 Fixes - **postgrest:** avoid instantiation depth errors for large relationship unions ([#2701](https://github.com/supabase/supabase-js/pull/2701)) ### ❤️ Thank You - Han Qiao @sweatybridge ## v2.117.1 ## 2.117.1 (2026-09-23) ### 🩹 Fixes - **auth:** return stored session when a refresh loses to another tab ([#2698](https://github.com/supabase/supabase-js/pull/2698)) ### ❤️ Thank You - Katerina Skroumpelou @mandarini ## v2.117.0 ## 2.117.0 (2026-09-22) ### 🚀 Features - **auth:** forward options.mediation to navigator.credentials.get in signInWithPasskey ([#2675](https://github.com/supabase/supabase-js/pull/2675)) - **auth:** enable passkey API by default and deprecate experimental passkey opt-in ([#2695](https://github.com/supabase/supabase-js/pull/2695)) ### ❤️ Thank You - fadymak - James Argarin - Katerina Skroumpelou This PR was created automatically. Co-authored-by: supabase-workflow-trigger[bot] <266661614+supabase-workflow-trigger[bot]@users.noreply.github.com> |
||
|
|
6ef729cb5c |
feat(storage): versioning bucket modals (FE-4161) (#49205)
| # | Branch | Base | | - | ------ | ---- | | 1 | `feat/storage-versioning-private-alpha` — merged | `master` | | 2 | `feat/storage-versioning/002-bucket-form-fields` | `master` | | 3 | `feat/storage-versioning/003-bucket-modals` ◀ | 2 | | 4 | `feat/storage-versioning/004-object-versions-data` | 3 | | 5 | `feat/storage-versioning/005-file-preview-versions` | 4 | | 6 | `feat/storage-versioning/006-billing-storage-retention` | 5 | | 7 | `feat/storage-versioning/007-archived-objects-data` | 6 | | 8 | `feat/storage-versioning/008-archived-rows` | 7 | | 9 | `feat/storage-versioning/009-archived-preview-pane` | 8 | | 10 | `feat/storage-versioning/010-replace-file` | 9 | ## [3/10] Storage object versioning: wire into the bucket modals **Base:** `feat/storage-versioning/002-bucket-form-fields` (PR 2) ### This PR Mounts the object-versioning form section in the create and edit bucket modals behind the feature preview, and saves it. - create and edit bucket modals spread `bucketVersioningFormFields` into their existing form schema - lifecycle defaults to 30 days / 10 versions - edit adds a confirmation before suspending an actively versioned bucket ## Enabling object versioning on a new bucket and setting lifecycle policies https://github.com/user-attachments/assets/194f8319-4929-432e-8a50-206f180a77a8 ## Edit and suspend object-versioning https://github.com/user-attachments/assets/f31e1d34-9840-4f5a-a269-6a911214742d ## To reproduce 1. Make sure storage versioning is enabled under feature previews > Storage Versioning 2. Open Storage Bucket File explorer 3. create new bucket and enable Object Versioning 4. set lifecycle policy - Noncurrent version expiration: can be either empty or >1 - Retained noncurrent versions: can be either empty or between 1 and 100 and can't exist without "Noncurrent version expiration" 5. Open new bucket with object versioning and test changing lifecycle policies 6. Disabling object-versioning shows proper warning and updates `versioning_status` to SUSPENDED (it can never go back to DISABLED once it has been enabled on a bucket) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com> |
||
|
|
075c611463 |
chore: bump vulnerable dependencies (#51381)
## Summary - Bumps vulnerable transitive dependencies flagged by `pnpm audit`, one commit per dependency (lockfile only, no permanent overrides): proxy-addr, shell-quote, @fastify/busboy, @graphql-tools/executor-legacy-ws, @modelcontextprotocol/sdk, compression, http-cache-semantics, source-map-js, smol-toml, dompurify. - Updates `scripts/fix-audit-vulnerability.ts` to be agent-friendly: accepts a dependency name argument, adds `--json` (single JSON object on stdout, logs on stderr, never prompts) and `--help`. ## Not fixed The remaining audit findings could not be resolved by this script. Some are blocked by `minimumReleaseAge` (braces, node-forge, sprintf-js); others stay vulnerable even with an override and need a parent dependency update or scoped override. ## Test plan - [ ] CI passes (typecheck, lint, prettier) - [ ] `pnpm audit` shows fewer findings than on master 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
|
|
6c6b19c6c6 |
chore(studio): report empty-body GET 200s to Sentry with a no-store probe (#51123)
<!-- ccr-slack-attribution --> _Requested by **Ivan Vasilov** · [Slack thread](https://supabase.slack.com/archives/C063LNYJJKS/p1790710416069689?thread_ts=1790710416.069689&cid=C063LNYJJKS)_ **Before:** When a Studio API GET comes back as a 200 with an empty body, openapi-fetch hands the caller `{}` and we only see the downstream crash, with no record of the response that caused it. **After:** The first time this happens for an endpoint in a page session, Studio sends one Sentry warning, `Empty response body on successful API request`. It carries the response metadata, browser state, resource timing, and the result of a single `cache: 'no-store'` refetch. What the caller receives is unchanged. ## Problem Studio crashes trace back to GET requests that return 200 with an empty body, which openapi-fetch turns into `{}`. They are heavily skewed to Firefox and Safari. The leading hypothesis is browser cache revalidation (Express weak ETags, no `Cache-Control` on api.supabase.com), but nothing confirms it yet. The `no-store` probe tells the two cases apart: if the refetch has a body, the browser cache is the likely culprit; if it is also empty, the server or the edge is sending empty bodies. This data should show whether the fix belongs on the API side or the Cloudflare side. Context: #51041 (closed) tried to guard the crashing call sites instead. ## Needs API-side change to be fully useful Cross-origin, Studio can only read CORS-safelisted response headers, and resource timing sizes read as zero. If api.supabase.com sends `Access-Control-Expose-Headers: ETag, cf-ray, cf-cache-status, x-request-id` and `Timing-Allow-Origin: <studio origin>`, this event will also carry the ETag, cf-ray, and cache status, plus the real transfer and body sizes and the negotiated protocol. Until then, those fields read as `null` or `0`. ## Solution - `data/empty-body-diagnostics.ts` (new): `reportEmptyBodyResponse({ request, response, schemaPath })`. - Runs only for `GET` and only when `IS_PLATFORM`. Empty POST/201 bodies are legitimate. - Reports at most once per templated endpoint per page session (module-level `Set`). - Endpoint: openapi-fetch's `schemaPath` (e.g. `/platform/projects/{ref}/settings`), passed through `templateEndpointPath`. That function drops the query string and hash, replaces the segment after `projects`/`organizations`/`branches` with `{ref}`/`{slug}`/`{branch}`, and replaces UUIDs, numeric IDs, and 20+ character alphanumeric IDs with `{id}`. I used `schemaPath` rather than the request URL so user-chosen names (bucket names, function slugs) never end up in tags or fingerprints. - Probe: one plain `fetch(new Request(request, { cache: 'no-store', ... }))` with a fresh `X-Request-Id` and a 10s `AbortController` timeout. `AbortSignal.timeout` isn't available in older Safari. The probe bypasses the openapi-fetch middleware, so it can't recurse. Only the body's byte length is recorded, never its contents. - Event: `level: 'warning'`, `fingerprint: ['empty-body-response', endpoint]`, `tags: { endpoint, probe_has_body, empty_body_diagnostic: 'true' }`, where `probe_has_body` is `true` / `false` / `error`. `extra` holds: - the request: method, status, `response.type`, `redirected`, and the original `X-Request-Id` (for API log lookup) - response headers: `content-type`, `cache-control`, `last-modified`, `expires`, `content-length`, `etag`, `cf-ray`, `cf-cache-status`, `x-request-id` - browser state: `visibilityState`, `navigator.onLine`, the navigation type, ms since navigation start, and whether the page was restored from bfcache - the latest `PerformanceResourceTiming` for the URL (transfer, encoded, and decoded size, `nextHopProtocol`, `responseStatus`) - the probe: status, request ID, body length, `content-length`, `content-type`, or the error name - Fire-and-forget: everything is wrapped in a `try`/`catch`, and the caller does not await it. - `data/fetchers.ts`: the `onResponse` middleware passes `{ request, schemaPath }` to `normalizeEmptyBodyResponse`, which calls the reporter in its empty-body branch and also for a 200 that carries `Content-Length: 0`. openapi-fetch short-circuits that case to `{}` the same way, so it is the same symptom. The return value is unchanged in every branch. - `packages/common/sentry.ts`: `filterSentryEvent` normally keeps only 1% of events that aren't page crashes. It now sends events tagged `empty_body_diagnostic` unsampled, with `codeSampleRate: '1'`. A once-per-session warning would barely show up at 1%. Consent and platform gating and the third-party filter still apply. www and docs also use `filterSentryEvent`, but only Studio's reporter sets this tag, so sampling for them and for every other Studio event is unchanged. Sentry config: Studio's `beforeSend` doesn't otherwise drop this message. It has no exception values, so the no-stack-trace filter doesn't apply, and it matches no `ignoreErrors` entry. ## Review instructions 1. Check `normalizeEmptyBodyResponse` in `data/fetchers.ts`: the reporter is `void`-called and its return value is untouched. 2. Check `probe()` in `data/empty-body-diagnostics.ts`: only `byteLength` is read from the body. The probe reuses the original request's headers and credentials (same auth as the original GET). 3. Check `filterSentryEvent` in `packages/common/sentry.ts`: only the `empty_body_diagnostic` tag skips sampling. 4. Tests: `data/empty-body-diagnostics.test.ts` and `packages/common/sentry.test.ts`. ## Verification - Unit tests (`data/empty-body-diagnostics.test.ts`, new): - path templating cases - `probe_has_body` `true` / `false` / `error` - the secret body content never appears in the Sentry call - one report per endpoint - non-GET and non-platform requests are skipped - no throw when `fetch` or Sentry throws - end-to-end through `client.GET`: still resolves `{}` and reports the `schemaPath`, for both a missing `Content-Length` and `Content-Length: 0` - `packages/common/sentry.test.ts`: tagged diagnostics are sent unsampled, untagged or false-tagged ones are still sampled, and they're still dropped without consent. These tests, plus the existing `normalizeEmptyBodyResponse.test.ts`, `handleError.test.ts`, and the rest of `sentry.test.ts`, pass (67 tests) under vitest 5 + jsdom. I ran them in a minimal harness, not the full `pnpm install` workspace, because the local checkout is sparse. - I ran TypeScript 7.0.2 (`--strict`) on the five touched files against the real `api-types`, with stubbed `common`/Sentry types. No errors in the touched files. - Prettier `--check` with the repo config passes, with and without `SORT_IMPORTS=false`. - Not run locally: the full studio typecheck, `lint:ratchet`, and knip. CI covers them. The change adds no `any`, no default exports, and no deps. ## Checklist - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01UefDak8XYLMi9aiEjDPXc5 --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
d1205a05e9 |
fix(studio): default cron HTTP timeout when timeout_milliseconds is omitted (#51385)
## Problem
`parseCronJobCommand` reads the timeout of an `net.http_get` /
`net.http_post` cron command like this:
```ts
const timeout = timeoutMatch?.[1] || ''
// ...
timeoutMs: Number(timeout ?? 1000),
```
When the command has no `timeout_milliseconds` argument, `timeout` is
`''`, which isn't nullish, so the `?? 1000` fallback never applies and
`timeoutMs` becomes `Number('') === 0`.
`timeout_milliseconds` is optional in pg_net, so this is common for jobs
created in SQL, e.g.:
```sql
select cron.schedule('ping', '* * * * *', $$ select net.http_get(url:='https://example.com/health') $$);
```
Opening such a job in the cron editor shows a timeout of **0 ms**, and
saving fails validation (the field requires 1000 to 5000 ms) until the
user edits a value they never set.
## Solution
Use the parsed value when present, and otherwise fall back to pg_net's
default for `timeout_milliseconds` (5000 ms in current pg_net). That's
what the job actually runs with, so opening and saving it in Studio
doesn't change its behavior. It's also within the form's allowed range.
Added tests for the Edge Function and HTTP request paths without
`timeout_milliseconds`. Both fail on `master` (`timeoutMs: 0`), and the
existing cron tests still pass.
## Review instructions
1. In the SQL editor, run:
```sql
select cron.schedule('ping', '0 * * * *', $$ select
net.http_get(url:='https://example.com') $$);
```
2. Open Integrations > Cron > `ping` > Edit.
3. Before: the timeout field shows `0` and saving shows a validation
error. After: it shows `5000` and saves.
4. `pnpm --filter studio test
components/interfaces/Integrations/CronJobs/CronJobs.utils.test.ts`
## Checklist
- [x] I have read
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
- [ ] If I wrote a new docs topic or edited an existing topic, I used
the `/write-the-docs` or `/edit-the-docs` skill, which applies the docs
[style
guide](https://github.com/supabase/supabase/tree/master/apps/docs/style-guide)
|
||
|
|
22886fd304 |
feat(studio): add flag-gated general region selection (#51274)
## Problem
We want to be able to show free-plan organizations a simplified region
selector that only lists general regions (Americas, Europe,
Asia-Pacific), controlled per organization through ConfigCat.
## Solution
- ConfigCat flags are now evaluated with `organization_slug` and
`organization_created_at` (Unix seconds) custom attributes, so flags can
target and bucket by organization.
- `organization_created_at` is read from `GET
/platform/organizations/{slug}`, fetched only for free-plan
organizations, since the organization list response doesn't include it.
- Two flags:
- `freeTierGeneralRegionEnrollment`: the organization is enrolled
(control or test).
- `freeTierGeneralRegionSelection`: the organization sees only general
regions.
- For enrolled free organizations, the region selector stays in its
loading state until flags have been evaluated with the organization's
creation time, so specific regions aren't shown and then removed.
- In the test variant, the selector hides specific regions and shows a
footer linking to the plan upgrade panel. High Availability keeps its
own region list.
- Telemetry: new `free_tier_general_region_experiment_exposed` and
`free_tier_general_region_upgrade_clicked` events, and
`freeTierGeneralRegionExperiment` / `regionSelectionType` properties on
`project_creation_simple_version_submitted`.
- `created_at` is added to `OrganizationSlugResponse` in the generated
platform types, matching the API.
## Review instructions
1. With both flags off, open `/new/[slug]` for a free organization and
confirm the region selector is unchanged.
2. Using the dev toolbar, set `freeTierGeneralRegionEnrollment` and
`freeTierGeneralRegionSelection` to `true`. Confirm only general regions
are listed and the footer links to the billing plan panel.
3. Set `freeTierGeneralRegionSelection` to `false` and confirm the full
selector is shown.
4. Repeat with a paid organization and confirm the full selector is
always shown.
|
||
|
|
ffe1ebc940 |
fix(studio): do not ignore requested model if available in base (#51388)
## Problem The model selection logic in `generate-v4.ts` was incorrectly ignoring the requested model even when it was available in the base model set. The condition checked for access to advanced models or throttling in a way that would force fallback to the default base model even when the requested model was already a base model. ## Solution Reordered the logical condition to first check if the effective model is a base model ID, and only apply the access/throttle checks when the requested model is not already a base model. This ensures the requested model is respected when it's available. Also threaded the `effectiveModel` parameter through to the assistant response generator for better telemetry and debugging context. ## Review instructions 1. Check the logic change in `apps/studio/pages/api/ai/sql/generate-v4.ts` line 164 2. Verify the condition now correctly checks `isAssistantBaseModelId(effectiveModel)` first 3. Confirm `effectiveModel` is now passed to `generateAssistantResponse` for proper telemetry ## Checklist - [x] I have read [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
16bd06dfb8 |
fix(studio): silence status page errors when incident.io isn't configured (#51315)
Running Studio locally without the incident.io env vars produces a 500 from `/api/status-page` on every fetch, plus a server-side log and a client `console.error`. Retries and the 5-minute refetch keep repeating them, so the dev console stays noisy. **Changed:** - `lib/api/status-page.ts` – when `INCIDENT_IO_WIDGET_URL` is unset outside production, return an empty (degraded, short-cached) status page instead of throwing. The missing API key / status page ID log is also limited to production. Production behavior is unchanged. - `data/platform/status-page-query.ts` – remove the client-side `console.error`, which repeated the error that React Query already exposes **Added:** - Tests for the missing widget URL in dev (empty payload, no error log) and in production (still throws) ## To test - Run Studio locally in platform mode without `INCIDENT_IO_*` set: no status page errors in the terminal or the browser console, and `/api/status-page` returns 200 with empty arrays - Support form and project creation still render normally (no status banner, status page link points to status.supabase.com) Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |