mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 19:35:06 +03:00
codex/tanstack-parent-upgrade
624
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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> |
||
|
|
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> |
||
|
|
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.
|
||
|
|
b5c865521f |
feat(studio): notify users about the Terms of Service update (#51302)
## Problem Dashboard users need a notice about the Terms of Service update alongside #51106 and #51107. ## Solution Reuse the organisation landing-page notice pattern from #50397. A compact “We've updated our Terms of Service.” notice opens the explanation and agreement link through **Learn more**. Closing the notice or choosing **Got it** remembers dismissal in the browser with a new version-specific key. ```text Organisation landing page Notice → Learn more → Explanation and Terms of Service link Close / Got it → Remember dismissal ``` | After | | --- | | <img width="628" height="444" alt="CleanShot 2026-10-06 at 14 47 46@2x" src="https://github.com/user-attachments/assets/72922712-321f-4972-b20c-1a075e0745d0" /> | | _Banner_ | | <img width="1078" height="718" alt="CleanShot 2026-10-06 at 16 58 18@2x" src="https://github.com/user-attachments/assets/2109c2ab-e9b7-4855-8acb-42d5232cd002" /> | | _Dialog_ | ## Review instructions 1. Open `/organizations` or an organisation's `/org/<slug>` landing page in the hosted Studio preview. Expect the compact notice. 2. Click **Learn more**. Expect the explanation and a link to the Terms of Service. Escape closes the dialog without dismissing the notice. 3. Choose **Got it**, then reload. The notice stays dismissed. Repeat in a fresh browser profile using **Close banner**. 4. Open a project or an organisation settings page. The notice should not appear. |
||
|
|
20d6f2197f |
chore(studio): remove privacy policy notice (#51299)
I removed the Studio Privacy Policy update notice that #50397 added on 2026-09-16, when Privacy Policy v4 took effect. It has been up for almost three weeks, and the ToS v4 banner (#51109) goes out next. I did the same in #44380, removing the March 2026 privacy notice after 15 days. This is the exact inverse of #50397: the banner component and its test, the banner ID, the dismissal local storage key, and the org-landing path helper that only this notice used. ## To test Tested on Vercel preview: - [ ] In a fresh browser profile (no `privacy-policy-update-2026-09-16-dismissed` key), open `/organizations`: expect no Privacy Policy notice - [ ] Open `/org/<slug>`: expect no Privacy Policy notice and the project list renders normally - [ ] Open a project's Logs page: expect the logs deprecation banner behavior unchanged (only shows before its expiry) ## Linear - fixes GROWTH-1322 |
||
|
|
a9078612f2 |
fix(www): stop cross-zone link prefetch (#51066)
About 95% of the 404s served on supabase.com are App Router RSC prefetches (`?_rsc=`) that www `<Link>`s fire at paths another zone serves: `/docs`, `/dashboard`, `/library`, and the footer's `humans.txt`, `lawyers.txt` and `security.txt`. Next.js can't prefetch or client-navigate across multi-zone boundaries, so each prefetch 404s even though the link itself works. I turned every www link into another zone into a plain `<a>` and added a lint rule so new ones stay that way. **Changed:** - **Cross-zone links are plain anchors**: links that always leave www (literal `/docs`, `/dashboard` and `.txt` hrefs, absolute `https://supabase.com/dashboard` URLs, the `getDashboardCtaHref` CTAs) render `<a>`. Renderers whose href comes from data (nav, footer, plan and add-on CTAs, product cards) branch on `isCrossZoneHref`, which reads the zone list from `lib/rewrites.js`. In-zone links stay `<Link>` and keep prefetching. - **New literal links can't regress**: `www/no-cross-zone-link` errors on a `next/link` `<Link>` whose literal or template href points at another zone. It evaluates `lib/rewrites.js` as production, so `/docs` counts in every environment. - **Click tracking survives the full navigation**: `sign_in_button_clicked`, `start_project_button_clicked` and `www_pricing_plan_cta_clicked` now send with `keepalive`, like `sign_in_submitted` already did, so an immediate page load can't cancel them. The mobile nav Sign in and Start your project buttons used `legacyBehavior`, which never called their `onClick`: PostHog has no `Mobile Nav` location for either event in the last 30 days. Those clicks report from this PR on. - **Typecheck no longer crashes**: the functions page's default export inferred a type through `RealtimeLogs`'s unexported `Props`, which makes the native TypeScript compiler panic during `tsc --noEmit`. I exported `Props`. **Note:** the lint rule only sees literal hrefs. A new renderer whose href comes from data needs its own `isCrossZoneHref` branch, and review is the only check on that. ## To test `/docs` is only rewritten on production and absolute `https://supabase.com/...` links are cross-origin on a preview, so the preview proves the relative non-docs cases (`/dashboard*`, `/library`, the footer .txt files). `/docs/...` prefetches still appear on the preview because it has no docs rewrite. Tested on Vercel preview: - [x] Open `/` with the network tab filtered to `_rsc` and scroll to the footer: no requests for `/dashboard*`, `/library`, `/design-system`, `/kb`, `/evals`, `/humans.txt`, `/lawyers.txt` or `/.well-known/security.txt`, while in-zone ones such as `/pricing`, `/features` and `/blog` still appear - [x] Same check on `/pricing`, `/auth`, `/database`, `/storage`, `/realtime`, `/edge-functions`, `/blog` and a blog post: no `_rsc` requests to `/dashboard*`, `/library` or the footer .txt files - [x] Open the Developers dropdown on desktop and the mobile menu at 390px: no new `_rsc` requests to `/dashboard*` or `/library` - [x] Click header Docs, footer Humans.txt, the hero Start your project button and the pricing Free plan button: each lands where it did before (`/docs`, `/humans.txt` text, `https://supabase.com/dashboard/sign-up`, `https://supabase.com/dashboard/new?plan=free`). Signed out, the Free plan button lands on the dashboard sign-in with `plan=free&returnTo=%2Fnew` - [x] Click the hero Start your project button: the `/platform/telemetry/event` POST with `start_project_button_clicked` completes with a 2xx after the page starts navigating. 201 with the navigation held; on the real navigation the event still reached staging PostHog - [x] At 390px, open the mobile menu and click Sign in: a `/platform/telemetry/event` POST with `sign_in_button_clicked` and `buttonLocation: "Mobile Nav"` fires. Start your project in the same menu also sends `start_project_button_clicked` with `buttonLocation: "Mobile Nav"` - [ ] Signed in, load `/`: no `/dashboard/projects?_rsc=` request (not run: the preview origin has no signed-in session) - [x] Open the desktop Product dropdown and the Product section of the 390px mobile menu: Compute shows its Private Alpha badge and the other products show none (checks the master merge into `MenuItem`) After deploy, `/` and `/pricing` on supabase.com show no `_rsc` requests to `/docs*`, `/dashboard*` or `/library`. After a full day, the share of supabase.com 404s carrying `_rsc=` should drop from about 95% to under 10%, and `sign_in_button_clicked` and `start_project_button_clicked` should start showing a `Mobile Nav` location in PostHog. ## Linear - fixes GROWTH-1294 |
||
|
|
dcf266c360 | feat(docs): update search v2 ui (#51175) | ||
|
|
53ecbf9f2a |
chore: Add telemetry to search v2 user actions (#51146)
## Problem We need to collect data from search v2 experiment usage. ## Solution Add telemetry to search v2 modal being opened, closing, sending a query and clicking a search v2 result. <!-- ## Preview links If relevant, include links to changed pages for easy review access. Copy the preview base URL from the Vercel bot comment on this PR. Use the following table as an example template. | Site | Live | Preview | Search for | | -------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------- | | WWW | [/blog/your-post](https://supabase.com/blog/your-post) | [/blog/your-post](https://zone-www-dot-com-git-branch-name-supabase.vercel.app/blog/your-post) | unique phrase from the change | | Docs | [/docs/guides/your-page](https://supabase.com/docs/guides/your-page) | [/docs/guides/your-page](https://docs-git-branch-name-supabase.vercel.app/docs/guides/your-page) | unique phrase from the change | | Studio | [/dashboard](https://supabase.com/dashboard) | [/dashboard](https://studio-git-branch-name-supabase.vercel.app/dashboard) | unique phrase from the change | | Design system | [/design-system](https://supabase.com/design-system) | [/design-system](https://design-system-git-branch-name-supabase.vercel.app/design-system) | unique phrase from the change | | UI library | [/library](https://supabase.com/library) | [/library](https://ui-library-git-branch-name-supabase.vercel.app/library) | unique phrase from the change | | Knowledge base | [/kb/guides/your-page](https://supabase.com/kb/guides/your-page) | [/kb/guides/your-page](https://kb-git-branch-name-supabase.vercel.app/kb/guides/your-page) | unique phrase from the change | --> <!-- ## Additional context Optionally add any other context or screenshots. --> ## Review instructions 1. Open the preview link and add the search v2 flag query: `?docs-search-v2=search-v2-active` 2. Trigger all actions mentioned above 3. Telemetry data should be sent on the network tab ## 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 references [WORD_LIST](https://github.com/supabase/supabase/blob/master/apps/docs/WORD_LIST.md) and the docs [CONTRIBUTING](https://github.com/supabase/supabase/blob/master/apps/docs/CONTRIBUTING.md) guide <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Improvements** * Documentation search activity is now recorded when the dialog opens from the keyboard shortcut or search input, and when it closes. Search submissions include the query and whether results were found; selected results include their destination and the highlighted query. This adds visibility into key search interactions without changing how search results or highlighting work. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
94b8b06eb2 |
Clean up auto region selection experiment (#51121)
## Context Just cleans up the experiment that was introduced [here](https://github.com/supabase/supabase/issues/50851) - can clean up feature flag in ConfigCat thereafter too <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Project Creation** * Removed the “Best available” region option. Choose a specific region or smart group when creating a project; the selected region name appears in the selector. * Recommended badges remain visible on recommended regions. * **Telemetry** * Project creation events no longer include details about the removed region option or the initial region recommendation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
99103b3571 | feat: Add edge function and hooks for search V2 (#51103) | ||
|
|
bd9a0ff4e6 |
feat(orioledb): rename orioledb from Public Alpha to Public Beta in dashboard (#50975)
## Problem We need to rename orioledb in Dashboard. ## Solution - Update Studio copy/badges referencing OrioleDB from "Public Alpha" to "Public Beta" (project creation advanced config, restore-to-new-project, PITR empty state) - Remove the scheduled-backups block that hid backups for OrioleDB projects — OrioleDB now has WAL-G scheduled backups in beta, so that page should behave normally. PITR keeps its existing guard since PITR is not yet supported for OrioleDB. - Update the `useOrioleDb` telemetry property doc-comment to reflect the beta status - Update project-creation wizard test expectations/fixtures accordingly (`release_channel: 'beta'`) Marketing (`apps/www`) and docs (`apps/docs`) references to OrioleDB alpha status are being updated separately. <!-- ## Preview links If relevant, include links to changed pages for easy review access. Copy the preview base URL from the Vercel bot comment on this PR. Use the following table as an example template. | Site | Live | Preview | Search for | | -------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------------------- | | WWW | [/blog/your-post](https://supabase.com/blog/your-post) | [/blog/your-post](https://zone-www-dot-com-git-branch-name-supabase.vercel.app/blog/your-post) | unique phrase from the change | | Docs | [/docs/guides/your-page](https://supabase.com/docs/guides/your-page) | [/docs/guides/your-page](https://docs-git-branch-name-supabase.vercel.app/docs/guides/your-page) | unique phrase from the change | | Studio | [/dashboard](https://supabase.com/dashboard) | [/dashboard](https://studio-git-branch-name-supabase.vercel.app/dashboard) | unique phrase from the change | | Design system | [/design-system](https://supabase.com/design-system) | [/design-system](https://design-system-git-branch-name-supabase.vercel.app/design-system) | unique phrase from the change | | UI library | [/library](https://supabase.com/library) | [/library](https://ui-library-git-branch-name-supabase.vercel.app/library) | unique phrase from the change | | Knowledge base | [/kb/guides/your-page](https://supabase.com/kb/guides/your-page) | [/kb/guides/your-page](https://kb-git-branch-name-supabase.vercel.app/kb/guides/your-page) | unique phrase from the change | --> <!-- ## Additional context Optionally add any other context or screenshots. --> ## Review instructions ## 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) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Updates** * OrioleDB is now labeled as being in public beta rather than public alpha, and project creation selects the beta release channel. * Restore-to-new-project and Point-in-Time Recovery notices clarify that these features are unavailable for OrioleDB projects. * OrioleDB projects now follow the standard eligibility checks and page flow for scheduled backups. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
0daafca2ca |
feat(studio): status page banner (incident / maintenance / upcoming) (#51044)
## Summary * Adds a new global status banner (`StatusBanner`) driven by the [incident.io](<http://incident.io>) status page data, showing at most one of: an active incident, in-progress maintenance, or upcoming maintenance, in that priority order. * All three types are independently dismissible (persisted to a new localStorage key, `status-banner-dismissed-keys`); dismissal hides the banner for items still active, and a new incident reappears even if a related item was previously dismissed. * Only shows to users who are actually affected (based on their projects' regions) or when region data is incomplete (fails open), and is bypassed entirely by the existing emergency incident override. * Behind the existing `incidentIoStatusPage` ConfigCat flag — `AppBannerWrapper` renders this new banner instead of the legacy `StatusPageBanner` only when the flag is on; default behavior is unchanged. * This is PR 5b in a stacked series for Linear [FE-4057](https://linear.app/supabase/issue/FE-4057) — see that issue for full design context. ## Test plan * New unit tests (`StatusBanner.utils.test.ts`) covering banner-selection priority, dismissal-key handling, and copy generation * New MSW component test (`StatusBanner.test.tsx`) covering loading state, dismiss-and-persist, and the emergency-override path * `pnpm --filter studio run typecheck`, `lint:ratchet`, `pnpm knip --workspace apps/studio`, `pnpm test:prettier`, and relevant vitest suites all pass 🤖 Generated with [Claude Code](<https://claude.com/claude-code>) Co-Authored-By: Claude [noreply@anthropic.com](<mailto:noreply@anthropic.com>) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added status banners for relevant incidents and scheduled maintenance, including incident details, maintenance timing, and links to the status page. * Banners can be dismissed, and dismissed items stay hidden while new incidents or maintenance updates can still appear. * Upcoming maintenance banners appear within the relevant lead time, and maintenance timing is shown when available. * Emergency overrides display a warning banner without a dismiss option. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
4a941518e3 |
feat(studio): track Explorer runs and saves (#51004)
I added outcome events for Explorer query runs and successful manual notebook saves. Existing page visits and preview toggles do not show whether users complete queries or persist notebooks. **Changed:** - **Query usage:** Accepted runs from query tabs and notebook cells emit submitted and terminal outcome events with a shared run ID. Canceled confirmations emit no run events. - **Notebook adoption:** Successful manual saves emit created or updated events. Recreated notebooks count as creations. Unsaved drafts and failed saves emit neither. - **Event metadata:** Explorer action events use `Explorer` as their page title. **Note:** Assistant-generated saves are outside this PR. Custom properties omit SQL and notebook content. Page visits still carry the browser title, which can include a notebook name. ## To test Tested on the staging preview: - [x] Run valid and invalid SQL from an Explorer query tab. Each run emits one submitted event and one matching completed or failed event with the same run ID. - [x] Run database and Logs notebook query cells, then add a markdown cell. The query cells emit matching event pairs; the markdown cell emits no query event. - [x] Save a new notebook, then edit and save it again. The successful saves emit created and updated events. - [x] Cancel a guarded query. It emits no query run event. - [ ] Recreate a notebook deleted on the server after local edits. A successful save emits created, not updated. - [x] Inspect an Explorer action event request. Its page title is `Explorer`; page visits still use the browser title. - [ ] Force a notebook save failure. It should emit no save event. This case was not tested manually. ## Linear - fixes GROWTH-1298 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Analytics** * Explorer query runs are tracked for database and log queries, including whether they complete or fail. * Query activity is associated with its location in Explorer, such as a query tab or notebook cell. * Successful notebook saves are tracked as creations or updates. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com> |
||
|
|
93a262d185 |
Check region selection for project creation (#51012)
## Context Previously added telemetry for `selectedRegionOption` and `selectedRegionOptionType` [here](https://github.com/supabase/supabase/issues/50851) if the best available region option is available for users Opting to extend this telemetry (still just for Free plan orgs) irregardless if best available region was selected and include `initialRecommendedRegion` Main thing to understand is what regions users are spinning projects up in outside of the recommended option ## To test - [ ] Verify the telemetry network request after creating projects - [ ] Non-free plan: Telemetry request doesn't have `initialRecommendedRegion` in the payload - [ ] Free plan: Telemetry request has `initialRecommendedRegion` in the payload - Sends correctly if best available region option is available (default behaviour for staging) - Sends correctly if best available region option is NOT available (override with dev tools the configcat flag) |
||
|
|
3f205627e0 |
feat(library): redesign the site around the block catalog (#50372)
## 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 — the visual redesign itself. Part 5 of 6 in a stack that splits the library redesign into reviewable pieces. The four PRs beneath it carry the build, content and Markdown work; what's left here is layout, navigation and styling. ## What is the current behavior? The library is laid out like a documentation site: a sidebar tree of framework folders, a homepage that lists links, and a guide page that opens with prose. That shape suits reference material, but the library's job is to help someone find a block and install it — and the sidebar is the only way to discover one. ## What is the new behavior? The homepage is the catalog itself — blocks grouped by what they do (authentication, database, storage, realtime, messaging, AI, foundations) rather than by framework, each with a preview of what it renders, filterable by category. Navigation moves into a site header whose Explore menu opens the same categories, so the catalog is reachable from any page and the per-page sidebar tree is gone. A guide opens with what the reader came for: the block's name, the install command, and a preview pane with tabs — the running component and its files — before any prose. The file tree that used to sit mid-page under "Folder structure" is one of those tabs. Every guide also offers a copy of the agent prompt that points at its Markdown. Getting-started pages get the same treatment: the quickstart is now a framework-tabbed walkthrough rather than a wall of setup links. ## Additional context `BlockOverviewTabs` renders Preview and Files here. #50369, stacked on top of this one, adds the third "What's added" tab — it is the only part of the redesign that depends on the new resource analyzer, which is why it sits above this PR rather than below it. Also removes what the redesign orphaned: the table-of-contents component and its `remark` / `mdast-util-toc` dependencies, and the sidebar nav and command-item configuration the new header replaced. The block source changes are typography only — auth card titles move from `text-2xl` to `font-medium text-lg tracking-normal` — which is what regenerates the auth registry artifacts. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a redesigned Supabase Library catalog with categorized blocks, framework-aware navigation, previews, file views, and installation actions. * Added framework-specific quickstart guides for Next.js, React, Vue, Nuxt, React Router, and TanStack Start. * Added copy-to-clipboard prompts, “Open in v0” actions, starter templates, and richer visual previews. * **Improvements** * Updated documentation layouts, FAQ content, typography, navigation, accessibility, and responsive behavior. * Improved mobile navigation, framework selection, and standardized block installation guidance. * Refined authentication and social-login block presentation with more consistent heading styles. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com> |
||
|
|
a47397d5fe |
fix(common): restore narrow Feature type (#50850)
The platform API now types `ProfileResponse.disabled_features` as `string[]` (since #48981), which collapsed the `Feature` union to plain `string`, so `isFeatureEnabled` accepted any string and typos went uncaught. **Changed:** - `Feature` is now a local `RuntimeFeature` union (the profile-driven flags) plus the keys of `enabled-features.json`, instead of deriving from the API type - `useIsFeatureEnabled` casts the merged runtime disabled list to `Feature[]`, since the profile field is now `string[]` The runtime feature list duplicates what the backend knows. Once the enum is restored in the API spec, `Feature` can go back to deriving from the generated type. ## To test - `pnpm typecheck` passes - Passing a bogus string to `useIsFeatureEnabled` / `isFeatureEnabled` is now a type error - Nothing behavioral changes, so a quick sanity check that the sidebar / billing / org settings still render is enough <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **No user-facing changes** * This update does not change the app’s visible features or behavior. It includes internal typing adjustments only. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |
||
|
+8 |
e273d2b818 |
chore(studio): move Explorer SQL Editor link to sidebar footer (#50829)
## What
- Moves the temporary "Switch to SQL Editor" button out of the Explorer
sidebar header into a footer section ("Looking for snippets?") with a
short explanation and an **Open SQL Editor** button.
- Replaces the header slot with a menu for the Explorer startup
preference (**Start page** / **SQL query**), instead of linking out to
account preferences.
## How to test
1. Enable the Explorer feature preview and open
`/project/<ref>/explorer`.
2. **Header menu:** click the ⋮ button next to the Explorer title. Pick
**SQL query**, then check that **Explorer startup** on `/account/me`
shows the same value (and vice versa).
3. **Footer:** click **Open SQL Editor**. You should land in the SQL
Editor with the **Back to Explorer** button in its title bar.
4. Open **Notebooks** or **Chats** in the sidebar and check that the
menu and footer are hidden there, like the old button was.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Choose whether the Explorer opens to the Start page or SQL query from
the Explorer preferences menu. Your selection is saved and retained when
you reopen the menu.
* Access the SQL Editor from the Explorer’s sidebar footer.
* Explorer preferences are available from the Explorer navigation
header.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Tyler <dshukertjr@gmail.com>
Co-authored-by: Nik Richers <nrichers@gmail.com>
Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Jordi Enric <37541088+jordienr@users.noreply.github.com>
Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Co-authored-by: Katerina Skroumpelou <mandarini@users.noreply.github.com>
Co-authored-by: Franek <franek@ferly.co.uk>
Co-authored-by: Franek Richardson <franek@supabase.io>
Co-authored-by: Michał Olszewski <35968924+charconstpointer@users.noreply.github.com>
Co-authored-by: Steven Eubank <47563310+smeubank@users.noreply.github.com>
Co-authored-by: Anthony Lio <lionnet.ant@gmail.com>
Co-authored-by: Joey Lei <6957385+leizerbeam@users.noreply.github.com>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
Co-authored-by: Samir Ketema <6003000+samirketema@users.noreply.github.com>
Co-authored-by: K-Dog (Kevin) <k.grueneberg1994@gmail.com>
|
||
|
|
a5ad2ce745 |
feat: log query/ingest insights (#50570)
We are doing a soft rollout for log pricing including log ingest and log querying. We currently only want to display usage/soft warnings, which is why the metrics are filtered out in some components. |
||
|
|
0d3b73794b |
Joshenlim/fe 4465 experiment with best available region selection (#50851)
## Context Adds a "Best available region" option in the region selector for the project creation form - Should only show up for free plan organizations (will be selected as the default option instead of the recommended option from GET `/available-regions`) - "Recommended" badges will also be hidden in this scenario - Behaviour should be status quo for non free plan organizations <img width="500" alt="image" src="https://github.com/user-attachments/assets/de0a183d-37c0-445d-98ca-c5aaf6353e73" /> ## To test Important to ensure that project creation still behaves as per usual - [ ] Free plan: Creating a project with "best available region" select creates the project if the recommended region from GET `/available-regions` - A quick way to check this is to swap to a paid org and see the "recommended" general region - [ ] Free plan: Can also create a project with other regions selected as per usual - [ ] Non free plan: Can create project as per usual - [ ] Verify that everything is status quo if configcat feature flag is off |
||
|
|
05a45dd1ed |
feat(studio): rename Replication to Pipelines (#50637)
## What kind of change does this PR introduce? Feature and docs update. ## What is the current behavior? The Dashboard lists Pipelines destinations under Database > Replication. Read replicas have moved to Infrastructure, but the temporary notices remain on the destinations page and new destination sheet. Closes PIPE-1021. ## What is the new behavior? The canonical Dashboard routes are Database > Pipelines, while legacy Replication list and detail URLs permanently redirect to the equivalent Pipelines routes. Navigation, command palette, shortcuts, pipeline links, docs, and current marketing copy use Pipelines. Read-replica notices and their obsolete dismissal state are removed. | Before | After | | --- | --- | | <img width="1024" height="759" alt="Replication Database Agua Basket Supabase" src="https://github.com/user-attachments/assets/53f9f565-1ed1-43e9-a7d9-b66b2a47e948" /> | <img width="1024" height="759" alt="2540" src="https://github.com/user-attachments/assets/14ab2d61-d01c-483f-9d4f-0ac286dae159" /> | The Management API, pipeline behaviour, replication logs, and Postgres replication terminology remain unchanged. ## To test - Open `/project/<ref>/database/pipelines` and confirm the Database navigation, page header, and pipeline breadcrumb say Pipelines. - Open `/project/<ref>/database/replication?source=bookmark#destinations` and a legacy pipeline detail URL. Confirm each redirects to the matching Pipelines URL while preserving parameters and fragments. - From the Pipelines page, open Add destination. Confirm no read-replica migration notice appears. - Open the Pipelines guide and confirm its Dashboard steps lead to Database > Pipelines. ## Before merge - [ ] Get changelog entry reviewed https://github.com/supabase/changelog/pull/262 and prepare to merge simultaneously <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added dedicated **Database > Pipelines** pages for pipeline lists and details. - Added permanent redirects from legacy Replication URLs to their corresponding Pipelines pages. - Read replica management links now open **Settings > Infrastructure**. - **Documentation** - Updated Pipelines setup, monitoring, troubleshooting, and usage guidance to reference the current dashboard locations. - Updated Realtime guidance to use **Database > Publications**. - **Updates** - Renamed dashboard navigation, breadcrumbs, commands, and keyboard shortcuts from **Replication** to **Pipelines**. - Removed the “Read replicas have moved” notification. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com> |
||
|
|
5bdfb8743c |
fix(telemetry): give warehouse_disabled the same schema and table counts as warehouse_enabled (#50643)
<!-- ccr-slack-attribution --> _Requested by **Pam Chia** · [Slack thread](https://supabase.slack.com/archives/C076KTY11DF/p1789979663384919?thread_ts=1789953229.116889&cid=C076KTY11DF)_ ## 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 (telemetry). ## What is the current behavior? **Before:** Disabling Warehouse fires `warehouse_disabled` with no properties at all, while enabling it fires `warehouse_enabled` with `schemaTargetCount` and `tableTargetCount`. Disables can be counted, but nothing says how much was being replicated when the user turned it off, so churn cannot be segmented by the size or shape of the setup being torn down. ## What is the new behavior? **After:** `warehouse_disabled` carries `schemaTargetCount` and `tableTargetCount` with exactly the same meaning they have on `warehouse_enabled`: schemas replicated in full, and tables replicated individually on top of those. A disable of a project replicating one whole schema plus two loose tables now reports one schema target and two table targets, so enable and disable volume line up on the same two properties. ## Additional context **How:** The counts are read once, when the user confirms the dialog, and held in a ref until the mutation succeeds. The setup mutation's own `onSuccess` invalidates the setup-status and replication-sources queries and awaits those refetches before the caller's callback runs, so anything read inside `onSuccess` already reflects the post-disable state and would report nothing replicated. The event is tracked from that hook-level `onSuccess` rather than a `mutateAsync` callback: the status refetch swaps the Disable card out of the panel, and mutate-level callbacks are skipped once the component has unmounted. The shape is reproduced from the `supabase_warehouse` publication through the same helpers the table picker uses — the publication's tables become a selection, and that selection is mapped back to targets against the project's selectable schemas. Counting distinct schemas and tables off the replicated-table list instead would put a different meaning behind the same property names: a fully covered schema would be counted as its individual tables rather than as one schema target, and the two events would no longer be comparable. Both properties are optional. The replicated-table list is assembled from four queries, and when they have not resolved the properties are omitted rather than sent as `0`, so "unknown" is never recorded as "nothing was replicated". Tests: unit tests for the extracted `buildSchemasWithTables` helper, and a component test that drives the disable dialog against a publication covering one schema in full plus one table from another. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_0197pGnhiAkhiiYiRxY3qVFY --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Pamela Chia <pamelachiamayyee@gmail.com> |
||
|
|
512201dcd0 |
chore(ui): remove the Classic Dark theme (#50387)
## What kind of change does this PR introduce? Chore. ## What is the current behaviour? Classic Dark remains available across the shared theme library and several apps. Studio now supports System, Dark, and Light as its theme modes, but still carries compatibility paths for Classic Dark. ## What is the new behaviour? - Removes Classic Dark from shared theme options, application commands, stylesheets, previews, examples, and replay handling. - Deletes the Classic Dark and faux Classic Dark stylesheets. - Removes the now-unused Classic Dark branches from Studio theme colour controls. - Migrates `classic-dark` to `dark` so first rendered frame renders Dark (not Light) | After | | --- | | <img width="1458" height="1778" alt="CleanShot 2026-09-18 at 11 07 40@2x" src="https://github.com/user-attachments/assets/679bf87f-a3c1-4599-ad2f-292d98d0b856" /> | ## To test 1. In Studio, open Account Preferences → Appearance. Confirm the available themes are System, Dark, and Light, and that theme colour controls still work in each resolved mode. 2. Set the `theme` local storage value to `classic-dark`, then reload Studio. Confirm it renders as Dark immediately and the stored value becomes `dark`. 3. Open the theme switcher in Design System, Learn, and UI Library. Confirm Classic Dark is no longer available and Light, Dark, and System still apply correctly. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Changes** * Removed the Classic Dark theme option from theme menus and settings across the application. * Classic Dark selections are automatically migrated to the standard Dark theme. * Updated theme documentation and demonstrations to list only System, Light, and Dark. * Removed Classic Dark styling and preview support; existing Dark, Light, and System themes remain available. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
e3c677fc5a |
feat(docs): track prompt panel copies in PostHog (#50482)
## 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 telemetry for `PromptPanel` to help us understand how people interact with our AI prompts better. Relates to DOCS-1393 Dashboard(restricted access): [Docs: AI prompt affordances](https://eu.posthog.com/project/34344/dashboard/957235) ## What is the current behavior? The docs homepage cover renders a setup panel with "AI Prompt" and "CLI" tabs, and guides render `AiPrompt` blocks. Both are built on the shared `PromptPanel`, whose copy button called `copyToClipboard` and nothing else. Copying was therefore unmeasured, while the neighbouring affordances (`ask_ai_clicked`, `agent_setup_clicked`, `copy_as_markdown_clicked`) are already instrumented. ## What is the new behavior? `PromptPanel` takes an optional `telemetry` prop. When it is set, the panel sends a new docs-owned event after a **successful** clipboard write, so instrumentation lives in the shared component instead of a forked homepage copy button. New event in `packages/common/telemetry-constants.ts`: | | | | --- | --- | | `action` | `docs_ai_prompt_copied` | | `source` | `homepage` \| `guide` \| `agent_setup` | | `tab` | `prompt` \| `cli` (omitted for panes outside that set) | | `promptId` | prompt id, when the panel comes from an `AiPrompt` block | Wired consumers: `HomePageCover` (`homepage`), `AiPrompt` (`guide` by default, plus `promptId`), and `AgentSetup` (`agent_setup`). No prompt body text and no PII is sent. Studio's existing `ai_prompt_copied` event is deliberately left alone: it has a different owner and surface, and merging the two would blend unrelated funnels. ### Proof it works ``` $ pnpm run test:local:unwatch features/ui/PromptPanel.telemetry.test.ts RUN v5.0.0 /apps/docs Test Files 1 passed (1) Tests 4 passed (4) Duration 775ms ``` ## Additional context Test plan, run against a local docs server with a stub telemetry endpoint so the request bodies could be read directly: | Case | Observed payload | | --- | --- | | Homepage, AI Prompt tab | `{"source":"homepage","tab":"prompt"}` | | Homepage, CLI tab | `{"source":"homepage","tab":"cli"}` | | Next.js quickstart `AiPrompt` | `{"source":"guide","tab":"prompt","promptId":"nextjs"}` | | `automate-with-agents/health` `AgentSetup` | `{"source":"agent_setup","tab":"prompt","promptId":"monitoring-agent-health"}` | | Clipboard write rejected | no request sent, error toast shown, button does not flip to "copied" | The failure case was re-checked with a control click on the same page after restoring a working clipboard, which did send the event, so the negative result is not just a missed handler. Also run: `turbo typecheck --filter=docs --filter=common` (passes), Prettier check on the touched files (passes), and ESLint on the touched docs files (no new findings; the one warning on `HomePageCover` is the pre-existing default export). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Successful prompt copies are now tracked across the homepage, documentation guides, and agent setup experiences. * Copy activity records the prompt’s source, selected format, and associated prompt when available, providing more complete usage insights. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Nik Richers <nik@validmind.ai> |
||
|
|
64ab76262e | feat(studio): exhaustion banner links to metrics (#50276) | ||
|
|
66d4b4c19b | chore(studio): remove expired tos update banner (#50533) | ||
|
|
0043e6f53b |
feat(studio): add Explorer onboarding and startup preference (#50493)
<img width="1454" height="920" alt="image" src="https://github.com/user-attachments/assets/a289b618-2bd2-4957-ac49-71d4e372d2cc" /> ## 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. ## What is the current behavior? Explorer always opens on its start page, without onboarding or a startup preference. ## What is the new behavior? Adds one-time onboarding with wireframe option cards and a collapsed Learn more section. Users can start on the Explorer start page or in a new SQL query tab, and change that choice in Account preferences → Dashboard. Preferences persist per account in the browser. ## Additional context How to test: 1. With Explorer enabled and fresh browser storage, open Explorer and select either startup option. Confirm Open Explorer follows the selection and onboarding stays dismissed after reload. 2. Change Explorer startup in Account preferences → Dashboard, then reopen Explorer. SQL query should create one normal query tab; Start page should restore the pinned home tab. 3. Use the keyboard to select an option and toggle Learn more. Expand it in a short viewport and check that the page scrolls normally. Validation: 235 tests pass, including 20 new cases; Studio typecheck and formatting pass. The local production build was stopped during compilation and was not verified locally. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added an Explorer onboarding experience with startup-view selection, guidance, and a Learn more section. - Added Explorer settings to choose between the Start page and SQL query views. - Explorer preferences now persist across sessions and accounts. - Explorer can open directly to a new SQL query when selected. - The Explorer Home tab is shown based on the selected startup preference. - **Accessibility** - Reduced-motion settings now disable the Explorer loading animation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
3e2d54eccb |
feat(studio): add Warehouse table management and disable (#50195)
## What kind of change does this PR introduce? Feature and UI polish. ## What is the current behavior? Warehouse setup uses a schema accordion for table selection. Once Warehouse is enabled, users cannot remove replicated tables or disable Warehouse from Studio. ## What is the new behavior? - Replaces the schema accordion with one grouped, searchable table selector. - Still allows for **Select all** and **Clear** actions for each schema. - Starts first-time setup with no tables selected and preselects current replicated tables when editing. - Adds support for removing previously replicated tables. - Adds a confirmed **Disable Warehouse** action. - Tracks successful Warehouse enable and disable actions. Disabling Warehouse removes its replication pipeline, publication, catalogue access, and foreign tables. Copied data remains in DuckLake storage until the user deletes it. Re-enabling a table rebuilds its data rather than reusing the retained copy. | Before | After | | --- | --- | | <img width="1024" height="759" alt="Integrations Test US East 1 testdw Supabase" src="https://github.com/user-attachments/assets/bded025b-1d45-41dc-8a35-9159baf8f9b7" /> | <img width="1024" height="759" alt="Integrations test Teamer Supabase" src="https://github.com/user-attachments/assets/69026d94-98a0-4878-ab58-2e9697296d93" /> | | <img width="1280" height="1323" alt="Integrations Test testdw Supabase" src="https://github.com/user-attachments/assets/3f71e754-1a87-4d58-a7b9-dd39d3e0ac5a" /> | <img width="1280" height="1323" alt="Integrations Regular AWS Teamer Supabase" src="https://github.com/user-attachments/assets/758ed48e-9ed6-45d3-ae94-e171147a21d5" /> | | _Feature did not exist_ | <img width="1024" height="759" alt="Integrations Regular AWS Teamer Supabase" src="https://github.com/user-attachments/assets/c977ac57-8b0c-4482-882b-69ad7602b5df" /> | ## Additional context Platform support for updating and disabling Warehouse was added in [supabase/platform#38190](https://github.com/supabase/platform/pull/38190). ### To test 1. Open `/project/{ref}/integrations/warehouse/overview` before setup. 2. Confirm **Tables to replicate** starts at zero and **Enable Warehouse** is disabled until a table is selected. 3. Confirm each schema's **Select all** and **Clear** actions update every table in that schema. 4. Enable Warehouse with a partial selection and wait for setup to complete. 5. Edit the selection, add and remove replicated tables, then confirm the saved selection is reflected in the publication. 6. Disable Warehouse, confirm the retention warning, and verify the integration returns to its initial state. 7. Re-enable Warehouse and confirm selected tables are rebuilt. 8. Trigger a replication pipeline limit error and confirm the inline guidance links to Database Replication. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added the ability to disable Warehouse from the setup panel. - Warehouse setup now starts with no table selections. - Editing a setup preselects replicated tables and supports updating selections, including removing tables. - Added searchable schema and table selection with screen-reader count announcements. - Added telemetry tracking for initial Warehouse enablement. - **Bug Fixes** - Warehouse disable failures now show an error while keeping the confirmation dialog open for retry. - Configuration updates now refresh related data automatically. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
cc540ff302 |
feat(studio): add safe theme colour controls (#49804)
## What kind of change does this PR introduce? Feature. ## What is the current behaviour? Studio Appearance preferences only select a theme mode. The underlying theme colours cannot be adjusted, and the existing proof of concept allowed unsafe combinations and introduced a bespoke Slider variant. ## What is the new behaviour? - Preserves the existing System, Dark, Light, and Classic Dark theme options. Classic Dark remains a fixed preset. - Adds four theme colour controls using the existing Supabase Slider unchanged. Each control presents a consistent 0 to 100 scale mapped to bounded light and dark ranges. - Previews colour changes while dragging and persists them once the interaction finishes, including rapid pointer gestures. - Stores light and dark overrides separately, validates stored values, clamps legacy values, and removes overrides that return to their shipped defaults. - Adds concise descriptions for Chroma, Contrast, Surface, and Elevation step, with a scoped Reset action shown only when the active theme differs from its defaults. - Keeps Slider in a stable shared chunk so production builds do not create a circular dependency between generated UI chunks. | Before | After | | --- | --- | | <img width="1448" height="1284" alt="CleanShot 2026-09-15 at 14 33 53@2x" src="https://github.com/user-attachments/assets/d55151c7-b2a9-40c6-9468-e77ae685ac38" /> | <img width="1454" height="1958" alt="CleanShot 2026-09-15 at 17 48 47@2x" src="https://github.com/user-attachments/assets/9d302e67-76cc-4341-948c-81713dea2e93" /> | ## To test 1. Open `/account/me` and scroll to Appearance. 2. Switch between System, Dark, Light, and Classic Dark. Confirm the same four modes remain available in the account theme menu. 3. Confirm Classic Dark retains its existing appearance and does not show theme colour controls. 4. In System, Dark, or Light, move each Theme colors slider to both ends. Confirm the dashboard previews the change, remains readable, and the theme cards do not shift or remount. 5. Reload the page and confirm colour changes persist separately for Light and Dark. 6. Return all sliders to their defaults, or select Reset, and confirm the Reset action disappears. 7. In System mode, change the operating system theme and confirm each resolved mode restores its own colour settings. --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com> |
||
|
|
99be7f92ce |
feat(studio): add Privacy Policy update notice (#50397)
## Summary Adds a compact Privacy Policy update notice for signed-in Studio users on organization landing pages. - Shows on `/org`, `/organizations`, and `/org/:slug` - Opens the approved policy explanation in a dialog - Links to the Privacy Policy and `privacy@supabase.com` - Persists acknowledgement in a dated local storage key - Stays off project and organization settings routes so it cannot cover product controls ## Why The Privacy Policy changes the data controller from Supabase, Inc. to Supabase Pte. Ltd. User rights and protections are unchanged. This restores the established authenticated Studio notification pattern: - [#35923](https://github.com/supabase/supabase/pull/35923): May 2025 Privacy Policy notice - [#43681](https://github.com/supabase/supabase/pull/43681) and [#43889](https://github.com/supabase/supabase/pull/43889): March 2026 Privacy Policy notice and design pass - [#45632](https://github.com/supabase/supabase/pull/45632): May 2026 Terms of Service notice - [#48524](https://github.com/supabase/supabase/pull/48524): current reusable Studio banner stack ## Release order The policy content and Studio notice deploy independently. Keep this PR in draft until [#50392](https://github.com/supabase/supabase/pull/50392) is approved, merged, and live. The notice appears immediately when this Studio change deploys. ## To test 1. Open Studio on `/organizations` or an organization project-list page. 2. Confirm the compact Privacy Policy notice appears. 3. Open **Learn more** and confirm the dialog copy and both links. 4. Select **Understood** or close the notice. 5. Reload and confirm the notice remains dismissed. 6. Remove `privacy-policy-update-2026-09-16-dismissed` from local storage and confirm the notice returns. 7. Open a project route and confirm the notice is absent. ## Verification - Prettier passes on changed files. - ESLint passes on changed Studio files. - Focused Vitest suites pass: 25 tests. - Studio Unit Tests & Build Check passes. - TypeScript & Lint, UI Tests, Studio Docker Build, dead-code, ratchet, and validation workflows pass. - All four self-hosted Studio E2E shards pass for both router implementations. - All deploy previews pass. - The Studio preview rendered the compact notice on the organization landing page without console errors. The dialog and dismissal flow still need an authenticated browser pass after the session redirected to sign-in. A direct local Studio TypeScript check reaches one existing unrelated error in `packages/ui-patterns/src/McpUrlBuilder/components/InstructionBlocks.tsx`; no changed file reports an error and the required TypeScript CI workflow passes. ## Measurement Success means signed-in users can find the updated policy from the organization landing experience without interrupting project work. The dated dismissal key confirms acknowledgement locally. CI protects the non-blocking route scope, and Privacy can monitor questions sent to `privacy@supabase.com` after release. --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Pamela Chia <pamelachiamayyee@gmail.com> |
||
|
|
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 --> |
||
|
|
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 --> |
||
|
|
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 --> |
||
|
|
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 --> |
||
|
|
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. |
||
|
|
c9e035910d |
Add HA toggle to enabled features (#50344)
## Context As per PR title - flags the HA toggle in project creation form behind a flag in enabled-features Behaviour should be status quo for both staging and prod <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a high-availability option to the project creation flow for eligible accounts when the feature is enabled. * The option is available through controlled feature configuration. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
25f411657d |
fix(telemetry): widen plan-presentation exposure event variant type to 5 variants (#50318)
<!-- ccr-slack-attribution --> _Requested by **Pam Chia** · [Slack thread](https://supabase.slack.com/archives/C076KTY11DF/p1789349119093319?thread_ts=1789349119.093319&cid=C076KTY11DF)_ ## 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 (telemetry type). ## What is the current behavior? The `pricing_panel_plan_presentation_experiment_exposed` event's `variant` property in `packages/common/telemetry-constants.ts` only types 3 of the experiment's 5 live variants (`'control' | 'parity' | 'gaps'`), even though the experiment source in `plan-presentation.ts` defines and actively uses 5: `control`, `parity`, `gaps`, `fullscreen`, `fullscreen-gaps`. The two full-screen variants are silently untyped in the telemetry catalog. ## What is the new behavior? The `variant` property is widened to `'control' | 'parity' | 'gaps' | 'fullscreen' | 'fullscreen-gaps'`, matching the exact casing of `PLAN_PRESENTATION_VARIANTS` in the experiment source, and consistent with how other experiment-variant unions in the same file (e.g. `rlsOptionVariant`) are kept in sync with their source enum. ## Additional context Linear: GROWTH-1234 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Gxb4n5ujMPeio1VmkowHc5 --- _Generated by [Claude Code](https://claude.ai/code/session_01Gxb4n5ujMPeio1VmkowHc5)_ Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
fb22534439 |
fix: share sentry crash policy and enable www reporting (#50232)
## Problem The website initializes Sentry only on the server and edge runtimes, leaving browser crashes unreported. Its crash-reporting setup also needs the same consent and third-party filtering policy that docs and Studio otherwise maintain separately. ## Fix Add www browser initialization and tagged crash capture for both Next.js routers, with accessible fallback focus. Move the shared consent/platform and third-party filtering into common/sentry, reuse it from all three apps, and remove the duplicated docs/www helpers and tests. Preserve each app's initialization and Studio's additional noise filtering, sampling, and sanitization. Include the source-map upload token in www's build cache inputs, and trigger the shared/www and Studio test workflows when the shared policy changes. ## How to test - Run `pnpm --filter www test ../../packages/common/sentry.test.ts lib/sentry-capture.test.tsx`: all 22 shared-policy and real-SDK capture tests passed locally. - Run `pnpm --filter studio exec vitest run lib/sentry-client-options.test.ts`: all 42 Studio options and policy-parity tests passed locally. - The www capture tests exercise the actual initializer and both router handlers with an in-memory transport, verify crash tags and fallback focus, and enforce consent. Removing initialization, capture calls, boundary tags, or consent gating was verified to fail these tests. - On a www preview with its DSN configured, accept telemetry consent and trigger temporary render errors in both routers. Verify they reach the www Sentry project with the boundary tag and readable stack traces. Formatting passes. Full local app typechecks encounter existing dependency/generated-file drift, with no diagnostics in changed files. Three unchanged TanStack mock call-count tests fail locally and reproduce against the pre-refactor implementation. Live Sentry ingestion and source-map uploads remain deployment checks. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Accessibility** - Error pages now automatically move focus to a clearly labeled error message, helping screen-reader and keyboard users understand when a page fails. - **Reliability** - Browser error reporting now captures application crashes more consistently across supported page types and navigation transitions. - Reporting respects consent and platform availability while filtering unrelated third-party failures. - **Testing** - Expanded automated coverage for error capture, reporting rules, consent handling, and accessible error-page behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
66e6cd1639 |
feat: capture Freebuff ad click ids (#50181)
## 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: ad attribution capture. ## What is the current behavior? Freebuff ad clicks arrive on supabase.com with a signed click id in `?bfcid=`. Nothing captures it, so those signups are unattributed. ## What is the new behavior? This PR captures `bfcid` and writes it to a cookie that, in production, is scoped so the management API receives it. The conversion is reported server-side on profile creation, in a separate change tracked in GROWTH-1217. Start with `enforceConsentDecision` in `packages/common/consented-url-cookie.ts`. It is the rule everything else hangs off, and `consented-url-cookie.test.ts` covers the state matrix. Capture: - `bfcid` is read on landing and held in `sessionStorage` until the consent decision resolves. Memory alone loses it when someone navigates before answering the banner. - Once consent is granted it goes into a cookie. In production on `*.supabase.com` that cookie is scoped to `domain=supabase.com`, and it is host-only elsewhere. It is written only after consent, which is the signal GROWTH-1217 relies on. - Values are validated with `/^bfc_[A-Za-z0-9._-]{1,508}$/`, the validator Freebuff publishes in their tag, so we never store a value their tag would reject. - `bfcid` is added to the first-touch attribution props, which feed pageview telemetry and are already consent-gated. Consent: - `enforceConsentDecision` reduces the decision to two states. Undecided and declined both clear the cookie, since neither has consent to point at. They differ in the retained value: an undecided visitor may still accept, so it waits for them. - `clearConsentedUrlCookie` drops the cookie. `discardConsentedUrlValue` also drops the retained value. - A module-level valtio subscription registers on import, guarded on `window` so it is inert during SSR. `packages/common/consent-state.ts` gains a generic `isResolved` flag and no vendor knowledge. A consumer acting on a decision needs to tell "not decided yet" from "decided against", which `hasConsented` cannot express alone. `applyPriorDecisionToSDK` now returns its promise chains, so its signature becomes `void | Promise<void>` and initialization awaits settlement before marking the decision resolved. Worth checking the call sites. ## Additional context 160 tests pass in `packages/common`. Typecheck and Prettier are clean locally on the changed files. CI is still running on the latest commit. Unverified: the clearing paths are covered by unit tests only. The consent SDK is short-circuited in local and preview builds, so they cannot be exercised outside production. An end-to-end conversion recorded by Freebuff is also unverified, since it needs the server-side change deployed. GROWTH-1216 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added consent-aware handling for Freebuff Ads click identifiers, retaining valid URL values until consent is resolved and storing them in a cookie after approval. - Added automatic cleanup when consent is denied or withdrawn, while preserving unrelated cookies. - Added support for capturing the click identifier in first-touch attribution data. - **Bug Fixes** - Improved consent initialization tracking so completion is reported after successful or failed resolution. - Added safeguards for restricted browser storage, cookies, and server-rendered environments. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Sean Oliver <882952+seanoliver@users.noreply.github.com> |
||
|
|
737b8595f2 |
Update API types (#50234)
## Problem platform, v1 and v2 have been already completely migrated and introduced some changes. Some types have been renamed, some outputs and inputs updated. ## Solution - Update the API types - Fix the TS errors ## Update Taking this over to unblock #50134, which needs the new scoped token permission ids from the regenerated types. - Merged `master`. - Regenerated `api-v2.d.ts` from the production spec. The previous files came from a local API that exposed a webhook events endpoint production doesn't have yet. Production has since added standardized 400 error responses on the v2 organization endpoints. `api-v1.d.ts` and `platform.d.ts` already matched production. - Fixed `verify-production-types`. It formatted the regenerated files in a temp directory outside the repository, so Prettier fell back to its defaults and the comparison could never match the committed files. It now passes the repository config explicitly. `pnpm api:verify-types` passes on this branch. - Verified locally: `pnpm typecheck`, `pnpm api:verify-types`, Studio unit tests. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Preserved descriptions when saving, sharing, moving, or unsharing notebooks, reports, SQL snippets, and saved queries. * Improved handling of empty or null values across notebook descriptions, billing usage, pooler settings, and infrastructure fields. * Improved read-replica connection handling, including read-only connection strings. * Updated storage configuration and capability handling to match current settings. * **API and Compatibility** * Updated organization, project, storage, OAuth, billing, and infrastructure data handling to match current API responses. * OAuth app creation and updates now require scopes. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> |
||
|
|
0bf22ee6fc |
chore(studio): update product naming (#50208)
workers -> compute <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added the Compute experience for deploying, viewing, managing, and monitoring compute instances. - Added Compute navigation, instance detail pages, secrets, logs, deployment dialogs, generated snippets, and CLI commands. - Added filtering, status, availability, and data-loading support for compute instances. - **Updates** - Updated labels, icons, links, feature controls, unified logs, and secret-deletion messaging to use Compute terminology. - Compute routes now replace the previous Workers routes and pages. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
1966209483 |
chore(deps): upgrade vitest to v5 (#49994)
Upgrades Vitest from 4.1.4 to 5.0.0 across the monorepo, fixes the handful of things v5 turned into hard errors, and drops the `vi.clearAllMocks()` boilerplate that v5's `clearMocks` default makes redundant. **Changed:** - `vitest`, `@vitest/ui`, `@vitest/coverage-v8` 4.1.4 → 5.0.0 (catalog) - `vi.mock` calls that lived inside `beforeAll`/`beforeEach`/test bodies moved to module scope (v5 throws on nested calls). Affects the Studio and docs setup files and four Studio tests. - `detectBrowser` test restores `navigator` via `vi.unstubAllGlobals()` instead of assigning `global.navigator`, which now reaches jsdom's getter-only property. - `RowEditor.utils.test.ts` restores its `JSON.stringify` spy. It used to leak a throwing mock for the rest of the file, which v5's coverage provider now trips over. A later test in the same file had been asserting the leak's side effect (valid JSON reported as invalid) and now asserts the correct behavior. - `@testing-library/jest-dom` 6.6 → 7.0.1. Its vitest type augmentation resolves through a peer now, so it lands on each package's own `vitest` instead of whichever copy pnpm hoisted. Fixes `toBeInTheDocument` type errors in dev-tools after the reshuffle. - `@testing-library/react` 16.0.0 → 16.3.3 for the React 19 peer range. - `vite: catalog:` added to dev-tools, www, and common. Without it they resolved a newer vite than the catalog pin, which forked a second vitest instance in the lockfile. There's now one. - ai-commands custom matcher types use v5's `Matchers<R, T>` form. - 110 test files: `vi.clearAllMocks()` removed from `beforeEach`/`afterEach` hooks, along with hooks that only did that and the imports they left unused. Calls that also reset/restore mocks are untouched. Second commit, mechanical. **Added:** - `.vitest/` to the root gitignore (v5 writes JSON/JUnit/HTML reporter output there) **Removed:** - `vite-tsconfig-paths` catalog entry and deps. Vitest 5 resolves tsconfig paths itself. Release-age note: this sat in draft with a temporary `minimumReleaseAgeExclude` entry for `vitest` and `@vitest/*` while 5.0.0 was inside the workspace's 3-day `minimumReleaseAge` window. That window has closed, so the exclusion is gone and nothing bypasses the release-age gate. **Perf** (local, medians of 3 runs, same machine): | Suite | v4.1.4 | v5.0.0 | |---|---|---| | studio | 144.1s | 141.7s (-2%) | | studio `--coverage` | 156.9s | 146.4s (-7%) | | ui-patterns | 6.27s | 5.07s (-19%) | | ui `--coverage` | 3.35s | 2.14s (-36%) | | www | 0.89s | 0.47s (-47%) | Studio is dominated by jsdom environment setup per file, which v5 doesn't change. `vitest doctor` recommends keeping the current pool config: the vm pools and `isolate: false` all break tests. ## To test - `pnpm install --frozen-lockfile` succeeds with no `minimumReleaseAgeExclude` entry for vitest. - CI: Studio unit tests, ui, ui-patterns, www, docs, and typecheck/lint should all be green. The lint ratchet was checked locally: warning counts on touched Studio files are identical to master. - `pnpm test:studio` locally passes with coverage (588 files, 6240 tests). - Open a Studio test that uses `toBeInTheDocument` in your editor and confirm no type errors on jest-dom matchers, in Studio and in `packages/dev-tools`. - Known pre-existing failures unrelated to this PR: one dev-tools test (`getEventCountBadge` capped pill) fails on master too. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Tests - Improved test coverage for JSON validation and mobile navigation behavior. - Updated test setup, cleanup, environment configuration, and matcher support across application and shared package suites. - Removed obsolete coverage for alternate MCP transport selection. ## Chores - Streamlined TypeScript path resolution and Vitest reporter output handling. - Updated testing libraries and Vitest tooling across documentation, Studio, website, and shared packages. - Added Vitest reporter output to ignored files. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com> |
||
|
|
a1686025b6 |
Joshenlim/fe 4291 keep unsaved notebooks accessible after page refresh (#49673)
## Context Changes here adds a "Draft" state for notebooks with a new `notebook-drafts` store - similar to how we handle query tabs in the explorer. This implies that if a user refreshes the tab while there's unsaved changes to notebooks, the changes can be persisted locally and the user will be able to continue from where they left off. This also implies that If you create a new notebook (OR open an existing notebook and make some changes) and refresh the browser, we no longer show the native browser confirmation dialog about discarding changes. We also reuse the existing confirmation dialog when saving a notebook if its draft has diverged from the server side content - just updated the language to be more generic rather than saying that the Assistant made changes <img width="429" height="238" alt="image" src="https://github.com/user-attachments/assets/5c392aed-1633-4428-8060-28f495a01f04" /> Also fixes an unrelated issue - renaming a notebook should mark the notebook as having unsaved changes (with the orange indicator) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit * **New Features** * Unsaved notebook edits are saved locally and restored when reopening Studio. * Drafts are scoped by project and protected from server changes through conflict detection. * Notebook tabs indicate unsaved changes, including drafts from unsaved notebooks. * **Bug Fixes** * Closing a tab with local edits prompts for confirmation and removes its saved draft. * Notebook save state reflects the server-confirmed update time. * Conflict messages clearly describe changes made on the server. * **Style** * Improved keyboard focus behavior for tab controls. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
db0e6b761b |
Joshenlim/fe 4304 bring database connections out of feature preview (#50107)
## Context
As per PR title - we're bringing Database Connections out of feature
preview and it'll live on the dashboard by default 🙂
Also deprecating the existing Ongoing queries panel which Database
Connections now supercedes.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Database Connections is now available without feature-preview
activation.
* The SQL editor’s “View running queries” option now links directly to
Database Connections.
* **Bug Fixes**
* Query cancellation and session termination now refresh database
activity data.
* **Removed**
* Removed the in-editor ongoing queries panel and its termination
controls.
* Removed the Database Connections promotional banner, preview
messaging, settings, and related telemetry.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
||
|
|
be030229bf |
feat(studio): add workers to unified logs FE-4281 (#49682)
## Problem Unified Logs does not expose Workers logs, so users cannot search Workers ingress, runtime, or build events alongside other services. ## Fix Add a Workers log type that classifies all three Workers OTEL streams. Gate the option and any persisted Workers filters with the existing Workers feature flag. ## How to test - Enable the Workers feature flag and open Unified Logs. - Select Workers from the Log Type filter. - Expected result: Unified Logs shows ingress, runtime, and build events with the Workers icon. - Disable the Workers feature flag and load a URL containing `log_type:eq:workers`. - Expected result: the Workers option and filter are removed, and Workers logs are not queried. - Run `./node_modules/.bin/vitest --run components/interfaces/UnifiedLogs/UnifiedLogs.queries.test.ts components/interfaces/UnifiedLogs/UnifiedLogs.utils.test.ts data/workers/worker-logs-query.test.ts` from `apps/studio`. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Workers as a selectable log type in Unified Logs. * Unified Logs now combines worker ingress, guest, and API streams under the Workers category. * Added a dedicated Workers icon and worker log filtering. * **Improvements** * Worker filters and URL parameters respect feature availability. * Worker details show relevant metadata while omitting unavailable HTTP fields. * Improved handling of worker log levels, statuses, and raw data. * Added stronger validation for unified log data. * **Tests** * Added coverage for worker routing, filtering, feature visibility, parsing, and metadata redaction. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |
||
|
|
b0601f9ab7 |
feat(storage): add object versioning feature flag and feature preview (#49202)
| # | Branch | Base |
| - | ------ | ---- |
| 1 | `feat/storage-versioning-private-alpha` ◀ | `master` |
| 2 | `feat/storage-versioning/002-bucket-form-fields` | 1 |
| 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 |
### PR 01
Adding feature flag for versioning.
- `UI_PREVIEW_STORAGE_VERSIONING` local storage key, allowlisted
- Feature preview entry gated on
`useFlag('storageVersioningPrivateAlpha')`
- `useIsStorageVersioningEnabled()`, following the existing
`useIsSqlEditorManualSaveEnabled` shape
<img width="910" height="604" alt="Screenshot 2026-08-19 at 11 33 45"
src="https://github.com/user-attachments/assets/5c51c3fa-6100-48e5-914d-63a9948a5024"
/>
Note: will improve the feature preview with an image once we approach
release.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
- **New Features**
- Added a Storage Versioning feature preview in the dashboard.
- Preview access is controlled by feature flags and is disabled by
default.
- Added descriptive information about Storage Versioning and its Private
Alpha availability.
- Added support for remembering the Storage Versioning preview setting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
11289328e5 |
add support for warehouse connection string (#49914)
Add support for connection string for warehouse. This PR gives the ability to enable warehouse on a project and also get the connection string to connect to. > This project is only available in staging for now and gated behind a feature flag <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a Warehouse connection option to the Connect dialog. - Select schemas and tables to replicate, with setup progress, error recovery, and retry support. - View copyable Warehouse connection details, credentials guidance, command-line instructions, and DuckLake setup scripts. - Warehouse availability is controlled by feature configuration. - **Tests** - Added coverage for Warehouse table selection, setup script generation, URL parsing, and connection configuration utilities. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Benjamin <5719034+bnjjj@users.noreply.github.com> Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com> |
||
|
|
c086fe0d3f |
fix(studio): stop duplicating access_token_creation_sheet_dismissed on Done (#50077)
<!-- ccr-slack-attribution --> _Requested by **Pam Chia** · [Slack thread](https://supabase.slack.com/archives/C076KTY11DF/p1788743741768969?thread_ts=1788743741.768969&cid=C076KTY11DF)_ ## 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 (telemetry). ## What is the current behavior? `access_token_creation_sheet_dismissed` (added in #49965) fires on every close of the "Generate token" sheet in `/account/tokens`, including a successful completion. The "Token created" step closes the sheet through a "safe" path (clicking **Done**), but `handleOpenChange` tracked the dismissed event on that path too: a 1:1 duplicate of the already-tracked `access_token_done_button_clicked` event, with `step: 'success'`. The event's `tokenType` property was also never meaningful: it is derived from a variable that is only set after a token is actually created and never reset, so on a first-attempt abandonment it is always `'none'` by construction, and on a later abandonment in the same session it carries the *previous* token's type. The sheet also force-closes when the permissions map fails to load. That close was indistinguishable from a user abandonment. Linear: [GROWTH-1196](https://linear.app/supabase/issue/GROWTH-1196/fix-access-token-creation-sheet-dismissed-duplicate-on-done) ## What is the new behavior? - The event no longer fires on **Done**. The token-created step already blocks Escape, outside click, and Cancel, so the event now only reflects the sheet closing before a token exists. - Dropped `tokenType` (never described the abandoned attempt, see above) and `step` (a constant `'form'` once Done stops firing it; it was also typed Numeric project-wide in PostHog, so its string values read as NULL in HogQL). - New properties, read from the live form at close time through a small `useImperativeHandle` ref on `NewScopedTokenForm` (`useForm` ownership stays inside the form component): - `resourceAccess` (`project` | `organization` | `account`): the in-flight scope selection. `account` is the classic-token path, so this carries what `tokenType` was meant to. It is the default `project` when the form is untouched, so filter on `isFormTouched` before reading it as intent. - `formStep` (`form` | `review`): which screen the user was on. The sheet-level `step` never captured this. - `isFormTouched`: whether any field was changed from its default. - `trigger` (`user` | `permissions_load_error`): the forced close on a failed permissions load now fires with its own trigger, so an endpoint regression shows up in the funnel instead of silently lowering `access_token_created`. - Fixed a double-fire on the load-error path: the form's error effect depended on the `onCancel` callback identity and re-ran on the sheet's close re-render (double toast, and a double event). It now reads the callback through a ref and depends only on `isError`, matching the existing `isReducedMotionPreferredRef` pattern in the same file. ## Additional context `NewScopedTokenSheet.test.tsx` asserts: Done does not emit the dismissed event; Cancel and Escape emit it with `trigger: 'user'` and the in-progress `resourceAccess` and `isFormTouched`; dismissing from the review screen reports `formStep: 'review'`; a 500 from the permissions endpoint emits exactly one event with `trigger: 'permissions_load_error'` and closes the sheet. `step` being typed Numeric in PostHog affects every event that sends a string `step`. That is a PostHog data-management fix handled separately, not in this PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01XW73umv73LrrKxFwwymSaH --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Pamela Chia <pamelachiamayyee@gmail.com> |
||
|
|
8654991847 |
feat(studio): additional events for scoped pat telemetry (#49965)
## 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? Adds PostHog tracking to the final step of the scoped PAT creation flow, after `access_token_created` fires. The token value is only ever shown once, so this measures whether users actually leave with a usable token. Three new events on the "Token created" step: | Event | Properties | | --- | --- | | `access_token_copied` | `tokenType` | | `access_token_stored_checkbox_clicked` | `tokenType`, `isChecked` | | `access_token_done_button_clicked` | `tokenType`, `hasCopiedToken` | - `isChecked` is the resulting state, so unticking the acknowledgement is captured too. - `hasCopiedToken` records whether the Copy button was used before finishing. Done is gated on the checkbox, not on copying, so this separates "copied it" from "ticked the box and left." - `tokenType` is threaded through from the sheet, which creates a classic token when resource access is `account` and a scoped one otherwise. It matches the existing `access_token_created` / `access_token_removed` property. ## Changes - `packages/common/telemetry-constants.ts` — three event interfaces, added to the `TelemetryEvent` union - `NewScopedTokenSuccess.tsx` — `useTrack()` plus a new `tokenType` prop; copy/acknowledge/done routed - `NewScopedTokenSheet.tsx` — `createdToken` state now holds `{ token, tokenType }` so the success step knows which - `NewScopedTokenSheet.test.tsx` — extended the two tests that already walk the full success flow with assertions and classic paths) ## Testing `pnpm test:studio` on `NewSco16 passing. Typecheck clean. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Analytics** * Added tracking for key access-token creation interactions, including copying tokens, selecting storage options, and completing the flow. * Tracking distinguishes between classic and scoped access tokens and records whether a token was copied before completion. * Added tracking when the access-token creation sheet is dismissed, including the current step. * **Behavior** * Existing copy, storage-selection, notification, and completion actions continue to work as expected. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com> |
||
|
|
9aaa753306 |
feat(studio): add telemetry for explorer/sql editor temporary switch buttons (#49898)
## Summary Add PostHog event tracking for the two new buttons introduced in PR supabase/supabase#49698 that allow users to temporarily switch between the Explorer and SQL Editor: * **Explorer button**: "Back to SQL Editor" button in the Explorer sidebar title bar now fires `explorer_temp_access_sql_editor_clicked` event * **SQL Editor button**: "Back to Explorer" button in the SQL Editor title bar (shown during temporary visits) now fires `sql_editor_back_explorer_clicked` event Both event interfaces follow the repo's telemetry-standards conventions, carrying only `groups: TelemetryGroups` property with no additional custom properties. ## Test plan - [X] Verify `explorer_temp_access_sql_editor_clicked` event fires in PostHog when clicking "Back to SQL Editor" button in Explorer - [X] Verify `sql_editor_back_explorer_clicked` event fires in PostHog when clicking "Back to Explorer" button in SQL Editor - [X] Run typecheck: `pnpm typecheck` passes without errors - [X] Run lint: `pnpm lint --filter=studio` passes ## Issue Resolves [FE-4213](https://linear.app/supabase/issue/FE-4213/explorer-set-up-telemetry-for-metrics-where-appropriate) ## Summary by CodeRabbit * **Analytics** * Added tracking for navigation from the Explorer to the SQL Editor. * Added tracking for returning from the SQL Editor to the Explorer. |
||
|
|
5db8a0e960 |
feat(studio): instrument sign-in attempts and failures (#49853)
The /sign-in page emitted only a pageview on entry and the success-side `sign_in` event on exit: failed or abandoned attempts were invisible, so "never interacted" and "tried and failed silently" could not be told apart in the sign-in funnel. I added an unsampled `sign_in_submitted` event at every initiation point and classified failure capture via `dashboard_error_created` with a new `signin` origin. **Changed:** - **Submit attempts observable**: `sign_in_submitted` (method: `email`, provider id, `sso`, or partner) fires from the DOM submit handler on the password and SSO forms (so submits that fail client-side validation still count), and from the OAuth, custom-provider, and partner initiation handlers. - **Failures classified**: each sign-in error path feeds the existing funnel-error pipe with origin `signin` and a controlled reason slug (`invalid_credentials`, `email_not_confirmed`, `captcha_failed`, `sso_provider_not_found`, ...). GoTrue auth errors now classify via their numeric `status`, guarded so transport failures (`status: 0`) stay `network_error`. - **Attempt events survive the OAuth redirect**: the telemetry event POST sends with `keepalive` (scoped to `sign_in_submitted`, since keepalive requests share a per-page in-flight body quota), so a dispatched request is no longer aborted by the provider navigation; send rejections are caught centrally instead of surfacing as unhandled rejections. The fetch still dispatches after an async token lookup, so preview testing verifies the GitHub-path event actually lands on the wire. - **Captcha rejection is no longer silent**: a rejected hCaptcha challenge resolves the stuck loading toast with an error message, emits `captcha_challenge_failed` (distinct from `captcha_failed`, which stays reserved for the auth server rejecting a submitted token), reports to error monitoring, and resets the captcha widget (previously: unhandled promise rejection and a spinner that never resolved). - **Partner method validated**: the partner sign-in page resolves the URL-hash value against the provider registry and forwards the canonical provider id into `method` on both `sign_in_submitted` and `sign_in`; anything unregistered records as `unregistered_partner`, so a crafted link can't poison the breakdown on either event. **Note:** failure events stay on the shared 10% `dashboard_error_created` sampling rate (a per-origin carve-out would break cross-source volume comparability); the unsampled attempt event carries the tried-vs-never-interacted signal at full volume. ## To test Tested on Vercel preview (studio-staging, wire-level network capture + staging ingestion check): - [x] On `/sign-in`, submit a bogus email + password: expect a `POST */platform/telemetry/event` request with `action: sign_in_submitted`, `method: email` in the network tab, plus an error toast. Observed: 201, auth returned 400 as expected. - [x] Submit with an empty password: expect `sign_in_submitted` to still fire (validation failures count as attempts). Observed: event fired with 201 and no auth call followed. - [x] Click "Continue with GitHub": expect `sign_in_submitted` with `method: github` on the wire before the provider redirect. Observed: the POST completed (201) before the browser landed on github.com, so the keepalive path holds. - [x] Negative case: fresh page load with no interaction fires no `sign_in_submitted`. - [x] Ingestion: all fired events (methods `email`, `github`, plus organic `sso` submits from a real login on the same preview) arrived in the staging project with the expected properties. - [x] Re-ran the email and GitHub paths on the scoped-keepalive build (`129bf8d`): both `sign_in_submitted` POSTs returned 201 (the GitHub one completed despite the provider redirect), and both events ingested into the staging project with the expected `method`/`category` properties. ## Linear - GROWTH-1165 (no `fixes` keyword on purpose: the evidence checks run on prod data post-deploy, and the issue closes manually after they pass) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Improved sign-in protection with more reliable invisible CAPTCHA handling. * Added sign-in submission tracking across password, SSO, partner, custom OAuth, and external-provider flows. * Added detailed classification for authentication, validation, CAPTCHA, provider, and network errors. * **Bug Fixes** * Sign-in now stops safely and resets CAPTCHA when verification fails. * Improved error reporting for failed sign-in attempts, including redirects and OAuth flows. * Ensured sign-in telemetry is delivered reliably during OAuth redirects. <!-- end of auto-generated comment: release notes by coderabbit.ai --> |