Commit Graph
36310 Commits
Author SHA1 Message Date
Alaister Young df2a806dab fix(studio): plumb Request.signal through toWebHandler as req.on('close'|'aborted')
Pages-router handlers that stream (e.g. /api/ai/sql/generate-v4)
wire client-abort by subscribing to Node IncomingMessage events:

  const abortController = new AbortController()
  req.on('close', () => abortController.abort())
  req.on('aborted', () => abortController.abort())

The toWebHandler shim built a plain NextApiRequest-shaped object with
no EventEmitter surface, so those calls crashed at runtime with
'req.on is not a function' on every request.

Surface a minimal EventEmitter (on/off/once/emit/removeListener/
removeAllListeners) that only honours the two events studio actually
uses ('close', 'aborted'), both wired to request.signal's abort
event. Other event names are accepted but never fire - good enough
for the handlers we forward through this shim.
2026-05-11 15:07:21 +08:00
Alaister Young 8c51b7f2fa feat(studio): land Web-streams body.ts + Web-fetch MCP API handlers
Both routes use streaming patterns that the buffering toWebHandler
shim can't represent, so they're hand-written against the Web
Standards Request/Response/ReadableStream APIs.

body.ts builds a multipart/form-data response whose body is a
ReadableStream. Each artifact file is read via createReadStream and
converted with Readable.toWeb, then drained chunk-by-chunk into the
same stream — no buffering. getFunctionsArtifactStore already
asserts self-hosted mode so the apiWrapper auth check (a no-op
outside IS_PLATFORM) is dropped.

mcp/index.ts swaps StreamableHTTPServerTransport (Node req/res) for
WebStandardStreamableHTTPServerTransport, the SDK's Web-fetch
variant introduced in @modelcontextprotocol/sdk 1.x. transport.
handleRequest now takes a Web Request and returns a Response
directly. Query parsing reads from URL.searchParams; headers pass
through unchanged.
2026-05-11 15:02:34 +08:00
Alaister Young d1d5a973f7 feat(studio): wire errorComponent on TanStack root route
Adds an ErrorBoundaryRoute that mirrors the existing react-error-
boundary Sentry capture and renders pages/500.tsx. TanStack's
errorComponent catches errors thrown during route load / component
render before the in-tree boundary mounts, so we report from both
layers; the route-level capture tags scope.setTag('routerError
Component', true) to keep the two streams distinguishable in Sentry.

Next's pages/_error.jsx is the pages-router catch-all - kept load-
bearing under Next but unreachable at runtime under TanStack.
2026-05-11 14:57:01 +08:00
Alaister Young b7366513e7 fix(studio): pin react vendor + add chunk-cycle build guard
Adds a 'react-vendor' manualChunks pin so React / React-DOM /
scheduler / jsx-runtime all land in one chunk. Without this, pinning
lucide-react alone leaves Rolldown free to inline React into the
lucide-react chunk for CJS interop, which shifts live-bindings
across the graph and surfaces as runtime errors like 'c is not a
function' at Alert-<hash>.js when the bundle is loaded in the
browser.

Adds an 'assertNoChunkCycles' build plugin that runs Tarjan's SCC
algorithm on the emitted client chunk graph and fails the build if
any unknown cross-chunk cycle exists. The existing CVA/TreeView/ui
cycle (entry 1 in CIRCULAR_IMPORTS.md) is allowlisted by chunk
basename so the build still passes while the structural fix is
pending; any new cycle blocks the build with a clear error
referencing the doc.
2026-05-11 14:51:56 +08:00
Alaister Young 5266561bb5 Merge remote-tracking branch 'origin/master' into alaister/tanstack-start
# Conflicts:
#	apps/studio/pages/project/[ref]/storage/vectors/index.tsx
#	pnpm-lock.yaml
#	pnpm-workspace.yaml
2026-05-11 14:37:39 +08:00
Alaister Young 71869444e4 docs(studio): add CIRCULAR_IMPORTS entry for lucide-react cycle
Companion to b8b86d599e (the vite.config pin). Documents the symptom,
root cause, workaround, and what a structural fix would look like, so
the chunk pin can be lifted alongside the CVA pin in the follow-up PR.
2026-05-11 14:34:04 +08:00
Alaister Young b8b86d599e fix(studio): pin lucide-react into its own chunk
Production runtime crashed with 'TypeError: e is not a function' at
folder-open-<hash>.js, blanking the page. Root cause is the same
chunk-level cycle pattern as the existing CVA workaround:
packages/ui re-exports Lucide icons, so the ui chunk transitively
pulls lucide-react; Rolldown then splits individual icons into
per-icon chunks that import createLucideIcon back from the ui chunk.
The cycle leaves the binding undefined at icon-chunk evaluation
time.

Pinning lucide-react into its own chunk breaks the cycle — the icon
chunks disappear and lucide-react only imports from rolldown-runtime.
CIRCULAR_IMPORTS.md gets a matching entry; the structural fix is the
same as for CVA and stays out of this PR.
2026-05-11 14:33:46 +08:00
Alaister Young 428b7b0764 chore: bump TanStack router/start and consolidate via pnpm catalog
Bumps @tanstack/react-router (1.169.1 -> 1.169.2) and
@tanstack/react-start (1.167.63 -> 1.167.65) to the latest patches.

Hoists three TanStack packages into the workspace catalog so the
versions stay aligned across consumers:

  @tanstack/react-router  - studio + ui-library
  @tanstack/react-start   - studio + ui-library
  @tanstack/react-table   - studio + ui-patterns + design-system

react-query is intentionally not included yet - consumers (studio,
docs, ui-library) sit on different 5.x versions and aligning them
deserves a separate decision.
2026-05-11 14:28:44 +08:00
Saxon Fletcher 19c5d467a8 github logo color (#45773)
Fixes logo so it makes use of currentColor

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

## Summary by CodeRabbit

* **Style**
* Improved GitHub icon color compatibility to properly adapt across
different UI contexts.

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45773)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-11 16:26:48 +10:00
Alaister Young f2cf9bf8d9 feat(studio): land /org/_/* and /project/_/* catch-alls
Adds the four TanStack routes for the wildcard org/project pages:
  routes/org.[_].tsx       - matches /org/_ exactly
  routes/org.[_].$.tsx     - matches /org/_/...
  routes/project.[_].tsx   - matches /project/_ exactly
  routes/project.[_].$.tsx - matches /project/_/...

Files use the path-as-filename form (org.[_].tsx) rather than the
nested-directory + index.tsx form because the directory form trips a
router-generator bug at getRouteNodes.js:132: when an index.tsx has a
bracket-escaped parent segment, originalRoutePath is wiped wholesale
and the escape info is lost - downstream the literal _ segment gets
stripped as if it were a pathless layout. Full rationale lives in the
comment block in routes/org.[_].tsx.

Next pages now accept either Next-style routeSlug (string[]) or
TanStack-style _splat (string) and normalise to the array shape, so
both runtimes can mount the same body.
2026-05-11 14:24:46 +08:00
Alaister Young 27f6d9255f fix(studio): forward url + options to next/router events shim handlers
Pages-router handlers expect (url, { shallow }) - previously dropped.
usePreventNavigationOnUnsavedChanges in particular reads the url arg
to remember the destination.

Adds mappings for beforeHistoryChange (-> onBeforeNavigate) and
hashChangeStart/Complete (filtered onBeforeNavigate/onResolved).

Documents the cancellation gap: subscribe is fire-and-forget so the
throw-to-cancel pattern in usePreventNavigationOnUnsavedChanges needs
useBlocker - flagged as a follow-up.
2026-05-11 14:08:36 +08:00
Alaister Young 52842d2324 feat(studio): land VercelIntegrationWindowLayout shell + 3 leaves
Adds the TanStack shell at routes/integrations/vercel.tsx and re-export
leaves for install, slug/marketplace/choose-project, and
slug/deploy-button/new-project. Placed at top-level rather than under
_app/ - Next getLayout for all three leaves wraps only in
VercelIntegrationWindowLayout (no AppLayout / DefaultLayout).
2026-05-11 14:05:42 +08:00
Alaister Young a5d7de9222 feat(studio): land assorted singleton routes + router shim default
Adds Path A re-exports for the remaining standalone leaves:

- project/$ref/merge (wraps ProjectLayoutWithAuth)
- project/$ref/api/index (redirect-only)
- _app/support/new + _app/support/link
- _app/new/index (inlines WizardLayout)
- new/$slug at top-level (no AppLayout in Next; uses PageLayout)
- integrations/github/authorize at top-level (no getLayout in Next)

Adds a default export to compat/next/router (module-scope SingletonRouter
shim) — surfaces NEXT_PUBLIC_BASE_PATH via basePath for the one consumer
(Support/DiscordCTACard) that reads it outside of React.
2026-05-11 14:03:32 +08:00
Alaister Young e449097918 feat(studio): land ProjectIntegrationsLayout shell + 4 leaves
Adds the TanStack shell at routes/project/$ref/integrations.tsx and
re-export leaves for index, $id, $id/$pageId, and $id/$pageId/$childId
(Path A — pages/... files retained per migration plan).
2026-05-11 13:59:47 +08:00
Alaister Young d85ffe50af feat(studio): land SettingsLayout shell + 15 leaves
routes/project/$ref/settings.tsx: SettingsLayout shell with
`settingsLayoutTitle` + `skipSettingsLayout` opt-out (scans whole
match chain).

Sub-shells:
- routes/project/$ref/settings/api-keys.tsx: ApiKeysLayout wrapping
  for both api-keys leaves (index + legacy), which both nest under
  ApiKeysLayout in their Next getLayout.

15 Path-A re-exports:
- 8 flat: general, api (skipSettingsLayout — redirect-only page),
  addons, compute-and-disk, dashboard, infrastructure, integrations,
  log-drains.
- 2 api-keys: index ('API Keys'), legacy ('API Keys (Legacy)') under
  the sub-shell.
- 2 jwt: index ('JWT Keys', wraps in JWTKeysLayout inline since
  jwt/legacy doesn't share it), legacy ('JWT Keys (Legacy)').
- 2 webhooks: index, \$endpointId (both 'Webhooks').
- 1 billing/usage.

All carry settingsLayoutTitle in staticData matching the per-page
title in Next's getLayout.
2026-05-11 13:56:16 +08:00
Alaister Young f03989dcb8 feat(studio): land LogsLayout shell + 17 leaves
routes/project/$ref/logs.tsx: LogsLayout sibling-file shell with
`logsLayoutTitle` + `skipLogsLayout` opt-out (scans whole match chain).

17 Path-A re-exports:
- logs/index: sets skipLogsLayout — page handles its own ProjectLayout
  (UnifiedLogs view + no-permission fallback). Refactored
  pages/.../logs/index.tsx so the inline <DefaultLayout> moves into
  `getLayout` instead of the body — TanStack's project shell already
  provides DefaultLayout, and rendering one inside the page would
  double-mount its providers (Sidebar, ProjectContext, etc).
- 13 log-type leaves: auth-logs, cron-logs, dedicated-pooler-logs,
  edge-functions-logs, edge-logs, pg-upgrade-logs, pgcron-logs,
  pooler-logs, postgres-logs, postgrest-logs, realtime-logs,
  replication-logs, storage-logs.
- 4 explorer leaves: index, recent, saved, templates.

All carry logsLayoutTitle in staticData matching the per-page title in
Next's getLayout.
2026-05-11 13:52:53 +08:00
Alaister Young 978b55f8cf feat(studio): land ObservabilityLayout shell + 11 leaves
routes/project/$ref/observability.tsx: ObservabilityLayout sibling-file
shell, reads observabilityLayoutTitle from leaf staticData via
useMatches({ select }).

11 Path-A re-exports, all share identical wrapping in Next
(<DefaultLayout><ObservabilityLayout title=X>{page}</ObservabilityLayout></DefaultLayout>),
no deltas: index (Overview), $id (Report), auth, database, api-overview
(API Gateway), edge-functions (Edge Functions), postgrest (PostgREST),
query-insights, query-performance, realtime, storage.
2026-05-11 13:49:09 +08:00
Alaister Young 35682be165 feat(studio): land /advisors/* product (shell + rules sub-shell + 4 leaves)
routes/project/$ref/advisors.tsx: AdvisorsLayout shell. Reads
`advisorsLayoutTitle` from leaf staticData and honours a
`skipAdvisorsLayout: true` opt-out for the rules subtree. Scans the
whole match chain (same pattern as functions.tsx — the flag is on the
sub-shell, not the leaf).

routes/project/$ref/advisors/rules.tsx: sub-shell that inlines the
inner body of `components/.../AdvisorRulesLayout.tsx` (AdvisorsLayout +
PageLayout with title/tabs/FeaturePreviewBadge). Skips the outer
DefaultLayout since the parent project shell already provides it.
Sets skipAdvisorsLayout: true. The existing AdvisorRulesLayout
component is left untouched for the Next runtime.

4 Path-A re-exports:
- advisors/performance, advisors/security: standard, title 'Linter'.
- advisors/rules/performance, advisors/rules/security: no staticData
  needed — the sub-shell handles wrapping.
2026-05-11 13:47:41 +08:00
Pamela Chia 5a5099adba fix(docs): always emit BreadcrumbList item field (#45744)
## Summary

Eliminates the Google Search Console "Missing field 'item' (in
'itemListElement')" critical error on 230 `/docs/guides/*` pages. The
schema was emitting `ListItem`s without an `item` field for intermediate
category nodes that lack a URL in the docs nav. Per [Google's
spec](https://developers.google.com/search/docs/appearance/structured-data/breadcrumb),
`item` is required on every BreadcrumbList position except the last leaf
— so url-less items are filtered out instead.

Also fixes a smaller quality gap surfaced during preview verification:
the `auth` section root in `NavigationMenu.constants.ts` was missing a
`url`, so auth trails were dropping the "Auth" breadcrumb level (`Docs >
Guides > JSON Web Tokens (JWT) > Overview` instead of `Docs > Guides >
Auth > JSON Web Tokens (JWT) > Overview`). Every other section root
already has a `url`; auth was the lone outlier.


## Testing

Tested locally via vitest (`pnpm --filter docs exec vitest run
lib/json-ld.test.ts`):
- [x] All-urls chain: every `itemListElement` has string `item` and
`name`
- [x] Leaf-url-mismatch: leaf uses `pathname` even when the chain leaf
URL differs
- [x] All-url-less chain: returns `null`
- [x] Empty chain: returns `null`

Tested on the preview deploy against 7 representative GSC-flagged paths:
- [x] `/docs/guides/getting-started/ai-prompts` — 4 positions, 0 missing
- [x] `/docs/guides/getting-started/ai-skills` — 4 positions, 0 missing
- [x] `/docs/guides/auth/jwts` — 4 positions, 0 missing (after auth fix:
includes "Auth")
- [x] `/docs/guides/auth/social-login/auth-google` — 4 positions, 0
missing (after auth fix: includes "Auth")
- [x] `/docs/guides/database/postgres-js` — 4 positions, 0 missing
- [x] `/docs/guides/storage/quickstart` — 4 positions, 0 missing
- [x]
`/docs/guides/platform/migrating-within-supabase/dashboard-restore` — 5
positions, 0 missing

Post-merge:
- [ ] validator.schema.org against deployed URL: 0 errors
- [ ] GSC "Validate fix" on the breadcrumb issue (1-2 week re-crawl
window)

## Linear

- fixes GROWTH-835

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved breadcrumb validation to filter incomplete entries and avoid
broken documentation links.
* Restored root link for the Auth navigation section so the Auth menu
item now navigates to /guides/auth.

* **Tests**
* Added comprehensive tests covering breadcrumb generation and edge
cases.

* **Refactor**
* Streamlined breadcrumb JSON‑LD schema generation for clearer output
and maintainability.

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45744)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-11 12:57:22 +08:00
Pamela Chia dc0cc42d14 chore(www): stop tracking auto-generated rss.xml (#45745)
## Summary

`apps/www/public/rss.xml` is committed to the repo AND rewritten on
every `pnpm dev`, `pnpm build`, and `pnpm typecheck` run via
`content:build` -> `apps/www/scripts/generateStaticContent.mjs`. Anyone
working in `apps/www` (or running `pnpm typecheck` from the monorepo
root) sees a phantom `M apps/www/public/rss.xml` in `git status` every
session. Easy to accidentally commit, otherwise has to be repeatedly
stashed.

The sibling `changelog-rss.xml` (written by the same script) is already
gitignored. This aligns the main blog rss with the same treatment.

## Changes

- Add `/public/rss.xml` to `apps/www/.gitignore` (alongside the existing
changelog-rss entries; renamed the section header from "Changelog
generated feeds" to "Generated feeds" to reflect what it now covers).
- `git rm --cached apps/www/public/rss.xml` so git stops tracking the
file. The on-disk copy is preserved for local dev.

## Testing

No behavior change — the file is still generated by `content:build` and
served from `public/` at build time.

- [x] `git check-ignore -v apps/www/public/rss.xml` resolves to
`apps/www/.gitignore:36`
- [x] `apps/www/public/rss.xml` still on disk after `git rm --cached`
- [ ] On a fresh clone + `pnpm install + pnpm --filter www build`, the
file regenerates and is served at `/rss.xml` on the resulting build
(Vercel preview will confirm via deploy).

## Linear

- fixes GROWTH-836

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

## Summary by CodeRabbit

* **Chores**
* Updated repository configuration to properly manage auto-generated
files.

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/45745)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-11 12:57:09 +08:00
AnaandAna 978fa7bdfb blog: Supabase is now an official ChatGPT app (#45602)
## 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?

New blog post

## What is the current behavior?

No blog post exists for this topic.

## What is the new behavior?

Adds a new blog post announcing that Supabase is now an official ChatGPT
app. Covers what you can do with the integration (database management,
branching, edge functions, etc.), how to get started, and supported
plans.

## Additional context

N/A

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

## Summary by CodeRabbit

## Documentation
- Published blog post announcing Supabase is now available as an
official ChatGPT app
- Describes 29 integrated tools for SQL operations, schema management,
security, project workflows, branching, edge functions, and
documentation search
- Includes setup guide, plan compatibility information, and video
tutorial

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

---------

Co-authored-by: Ana <ana1337x@users.noreply.github.com>
2026-05-08 23:49:25 +02:00
Ivan Vasilov 4dffe42967 feat: Add a color palette to design-system (#45721)
This PR adds a color palette to the Design system for easier reference.

<img width="1325" height="1200" alt="Screenshot 2026-05-08 at 17 18 51"
src="https://github.com/user-attachments/assets/7de77c15-f6c6-4691-9875-eea72919ff7d"
/>


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

* **New Features**
* Added an interactive color palette: displays named colors with 12
scale steps; click a swatch to copy its CSS variable and see brief
"Copied!" feedback.

* **Documentation**
* Added a "Color palette" section to the color usage docs with
instructions and an embedded palette for exploring and copying CSS
variables.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-08 21:12:48 +00:00
Ali Waseem c5666f8e76 fix(auth): toggle shortcut repeats (#45728)
## 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?

Remove unneeded checks and its handled by the shortcut

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

## Summary by CodeRabbit

* **Bug Fixes**
* Improved the empty state interface in the Third Party Auth integration
form, enhancing the display and alignment when no integrations are
available.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-08 22:16:24 +02:00
Guilherme SouzaandClaude Sonnet 4.6 2133134daa docs: update SDK reference docs from recent SDK changes (#45716)
## Summary

Updates reference docs based on recent **stable** releases across
supabase-js, supabase-flutter, and supabase-py. Only changes that landed
in a stable tag are documented.

## Changes analyzed

| SDK | Repo | Stable tag range | Notes |
|-----|------|-----------------|-------|
| js | supabase/supabase-js | `v2.105.0` → `v2.105.3` | Bug fixes and
type improvements; no doc-worthy API changes |
| dart | supabase/supabase-flutter | → `supabase_flutter-v2.13.0` |
`anonKey` deprecated → `publishableKey` |
| py | supabase/supabase-py | `v2.29.0` → `v2.30.0` | New: `.select()`
chaining on write builders |
| swift | supabase/supabase-swift | `v2.46.0` | Dependency bumps only |
| kt | supabase-community/supabase-kt | `3.6.0` | Test coverage
improvements only |
| csharp | supabase-community/supabase-csharp | `v1.1.2` | No changes |

> **Note**: The JS `storage.from().exists()` breaking behavior change
and `PostgrestError instanceof` fix were intentionally excluded — they
are only in the `v3.0.0-next` pre-release branch, not in any stable
`v2.x` tag.

## Documentation updates

### `apps/docs/spec/supabase_dart_v2.yml`
- Rename `anonKey` parameter → `publishableKey` in
`Supabase.initialize()` to match the deprecation in
[supabase-flutter#1360](https://github.com/supabase/supabase-flutter/pull/1360)
(landed in `supabase_flutter-v2.13.0`)
- Update Flutter example to use `publishableKey:` named argument
- Note that `anonKey` is still accepted but deprecated

### `apps/docs/spec/supabase_py_v2.yml`
- Add `.select()` chaining examples to `insert()`, `update()`,
`upsert()`, and `delete()` write builders, newly supported in
[supabase-py v2.30.0](https://github.com/supabase/supabase-py/pull/1383)
- Add notes to each write method mentioning select chaining capability

---

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

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

## Summary by CodeRabbit

## Release Notes

* **Documentation**
* Dart SDK: Updated client initialization to use `publishableKey`
parameter; deprecated `anonKey` remains supported for backward
compatibility.
* Python SDK: Added examples demonstrating how to chain `.select()` with
write operations (`insert()`, `update()`, `upsert()`, `delete()`) to
retrieve specific columns from modified rows.

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 15:12:30 -03:00
Charis d3d6dd0eda Revert "studio: debug logging for notice banner 2" (#45727)
Reverts supabase/supabase#45724
2026-05-08 17:32:19 +00:00
Charis cce46e15ab studio: debug logging for notice banner 2 (#45724)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Added diagnostic logging to banner components for internal monitoring
purposes.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-08 12:45:47 -04:00
Charis cf1e95dcd7 studio: maintenance banner for shared pooler 2026-05-13 (#45695)
Add a second notice banner (because we need the first one to show the
current ToS update). Scoped to ap-southeast-1 and sa-east-1.

Haven't linked to the StatusPage maintenance entry yet as it's not up;
the placeholder link is just to the generic StatusPage.

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

* **New Features**
* Added a second notice banner that alerts users to upcoming maintenance
for affected databases in specific regions; it appears conditionally
(based on affected projects) and can be dismissed—dismissal prevents it
from reappearing.
* The existing “Updated Terms of Service” notice remains unchanged and
continues to display on non–sign-in routes until acknowledged.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-08 15:35:32 +00:00
Alan Daniel 73286972fb feat(www): load _events mdx files on /events listing (#45176)
## 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?

The /events page only loads events from the Notion "Developer Events"
database and the Luma Community API. MDX files under `apps/www/_events/`
(including webinars like agency-webinar, sentry, datadog, figma-make)
are not surfaced on the listing, and past events could still appear
until the moment they ended because the filter compared against `now()`
rather than the current day.

Addresses
[DEBR-85](https://linear.app/supabase/issue/DEBR-85/events-page-powered-by-notion-page).

## What is the new behavior?

- New `getMdxEvents()` reads `apps/www/_events/*.mdx`, parses
frontmatter with `gray-matter`, and returns today-and-future events as
`SupabaseEvent`s.
- `/events` now merges Notion + mdx + Luma events.
- Past events are hidden across all sources by comparing against the
start of today (UTC) instead of `now()`, so events running today stay
visible throughout the day.

## Additional context

Links on mdx events point at the main_cta URL when it's an external
\`http(s)\` URL, otherwise fall back to the built \`/events/{slug}\`
page so on-demand recordings remain reachable.

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

* **New Features**
* Events can be sourced from MDX files and merged into site event
listings.
* Luma supports multiple calendars (community and hackathon) for richer
feeds.

* **Improvements**
  * Events now exclude anything before the start of the current UTC day.
  * Added a “Community Event” category filter and included it in counts.
  * Event title typography adjusted for improved readability.
* “Hosted by” text now only shows when hosts exist; host fallbacks
standardized.

* **Chores**
  * Build env updated to include hackathon API key.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-08 11:22:35 -04:00
supabase-supabase-autofixer[bot]andsupabase-workflow-trigger[bot] e46ee776b4 feat: update @supabase/*-js libraries to v2.105.4 (#45717)
This PR updates @supabase/*-js libraries to version 2.105.4.

**Source**: supabase-js-stable-release

**Changes**:
- Updated @supabase/supabase-js to 2.105.4
- Updated @supabase/auth-js to 2.105.4
- Updated @supabase/realtime-js to 2.105.4
- Updated @supabase/postgest-js to 2.105.4
- Refreshed pnpm-lock.yaml

---

## Release Notes

## v2.105.4

## 2.105.4 (2026-05-08)

### 🩹 Fixes

- **auth:** return null from getItemAsync on JSON parse failure
([#2336](https://github.com/supabase/supabase-js/pull/2336))
- **postgrest:** restore non-Error abort detection in fetch catch
([#2335](https://github.com/supabase/supabase-js/pull/2335))
- **realtime:** guard sessionStorage access in restricted-storage
browsers ([#2339](https://github.com/supabase/supabase-js/pull/2339))

This PR was created automatically.

Co-authored-by: supabase-workflow-trigger[bot] <266661614+supabase-workflow-trigger[bot]@users.noreply.github.com>
2026-05-08 18:02:58 +03:00
supabase-supabase-autofixer[bot]andsupabase-releaser[bot] d71717585e docs: update js sdk docs (2.105.4) (#45718)
Updates JS sdk documentation following stable release.
Ran `make` in apps/docs/spec to regenerate tsdoc files.

**Details:**
- **Version:** `2.105.4`
- **Source:** `supabase-js-stable-release`
- **Changes:** Regenerated tsdoc files from latest spec files

🤖 Auto-generated from @supabase/supabase-js stable release.

Co-authored-by: supabase-releaser[bot] <223506987+supabase-releaser[bot]@users.noreply.github.com>
2026-05-08 18:01:36 +03:00
Pedro RodriguesandClaude Sonnet 4.6 4ac0278b64 docs: rename Supabase agent plugin to Supabase Plugin for AI coding Agents (#45693)
## Summary

Renames the docs page title, sidebar label, description, and body text
from **"Supabase Agent Plugin"** to **"Supabase Plugin for AI coding
Agents"** across `plugins.mdx`, `ai-skills.mdx`, `mcp.mdx`, and the
navigation constants

More context in this [Slack
thread](https://supabase.slack.com/archives/C0254JUR2DU/p1778165488699219)

Close
[AI-710](https://linear.app/supabase/issue/AI-710/rename-supabase-agent-plugin-docs-title)

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

* **Documentation**
* Renamed the AI tool throughout docs and navigation to "Supabase Plugin
for AI Coding Agents" (previously "Supabase Agent Plugin").
* Updated getting-started and plugin pages, installation guidance, and
sidebar labels to use the new name while preserving existing links and
instructions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 17:53:06 +03:00
Ali WaseemandJoshen Lim f06b877ac6 feat(auth-users): add keyboard shortcuts to users page (#45650)
Closes
[FE-3173](https://linear.app/supabase/issue/FE-3173/add-keyboard-shortcuts-to-auth-users-page)

## Shortcuts

| Key | Action |
|---|---|
| `Shift+F` | Focus search input |
| `F C` | Reset filters |
| `Shift+R` | Refresh users |
| `S C` | Reset sort to default |
| `Mod+A` | Toggle selection on all loaded users |
| `Mod+Backspace` | Open bulk-delete confirm modal |
| `Esc` | Clear row selection + cell focus |
| `Esc` (panel open) | Close user details panel |
| `↑` / `↓` | Move focus into the grid; native arrow nav after |
| `Enter` (row focused) | Open user details panel |
| `I U` | Open Create user modal |
| `I I` | Open Send invitation modal |

## Test plan

- [ ] `Shift+F` focuses the search input
- [ ] `F C` clears keywords, user type, providers
- [ ] In the search input: Esc clears value, Esc again blurs
- [ ] `Shift+R` refreshes
- [ ] `S C` resets sort; no-op at default
- [ ] `Mod+A` toggles all loaded users when ≤ 20 are loaded
- [ ] `Mod+Backspace` opens the delete confirmation when a selection
exists
- [ ] `↑` / `↓` from cold load enters the grid; subsequent arrows
navigate cells
- [ ] `Enter` on a focused row opens the panel
- [ ] `Esc` with panel open closes it; without panel, clears selection +
cell focus
- [ ] `I U` opens the Create user modal
- [ ] `I I` opens the Send invitation modal
- [ ] All shortcuts appear in `Cmd+K`

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

* **New Features**
* Comprehensive keyboard shortcuts for user management (focus search,
refresh, reset filters, bulk select, open delete modal, close panel).
* Improved keyboard navigation in the user list with cell-level movement
and Enter-to-select behavior.
* Search input: Escape clears search/keywords and it can be focused
programmatically.
* Shortcut hint badges added to "Send invitation" / "Create new user"
dropdown items.

* **Chores**
  * Centralized refresh behavior for consistent interaction.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-05-08 08:49:53 -06:00
Ali WaseemandDanny White 0278672102 feat(studio): add Auth sub-page navigation chords (#45696)
## Summary
- Adds contextual `A + <letter>` chord shortcuts for jumping between
Authentication sub-pages while `AuthLayout` is mounted, mirroring the
existing database-nav chord pattern.
- Wires the shared `LIST_PAGE_*` shortcuts (focus search, create new,
reset filters, schema selector) onto the Auth list pages so they behave
like the Database list pages.
- Fills in the previously-missing `A + U` chord for the **Users** page
so every entry in the Auth menu has a chord.

Resolves
[FE-3187](https://linear.app/supabase/issue/FE-3187/add-a-u-keyboard-shortcut-for-auth-users-page).

## Auth navigation chords

Active anywhere under `/project/<ref>/auth/*`. Press `A` then the listed
letter.

| Page | Chord |
| --- | --- |
| Overview | `A` `O` |
| Users | `A` `U` |
| OAuth Apps | `A` `A` |
| Email | `A` `E` |
| Policies | `A` `P` |
| Sign In / Providers | `A` `I` |
| Passkeys | `A` `K` |
| OAuth Server | `A` `V` |
| Sessions | `A` `S` |
| Rate Limits | `A` `R` |
| Multi-Factor | `A` `M` |
| URL Configuration | `A` `L` |
| Attack Protection | `A` `T` |
| Auth Hooks | `A` `H` |
| Audit Logs | `A` `G` |
| Performance | `A` `F` |

## Auth list-page shortcuts

Each Auth list page opts into the shared `LIST_PAGE_*` registry — same
chords as the Database list pages (`Shift+F`, `Shift+N`, `F` `C`, `O`
`S`). Coverage matches the controls each page actually exposes:

| List page | Search (`Shift+F`) | New (`Shift+N`) | Reset filters (`F`
`C`) | Schema selector (`O` `S`) |
| --- | :---: | :---: | :---: | :---: |
| Custom Auth Providers | ✓ | ✓ | ✓ | — |
| OAuth Apps | ✓ | ✓ | ✓ | — |
| Policies | ✓ | — | ✓ | ✓ |
| Auth Hooks | — | ✓ | — | — |
| Redirect URLs | — | ✓ | — | — |
| Third-Party Auth | — | ✓ | — | — |

## Test plan
- [x] While anywhere under `/project/<ref>/auth/*`, every chord in the
navigation table jumps to the corresponding page.
- [x] On each list page in the second table, the marked shortcuts focus
the search input / open the create flow / reset filters / open the
schema picker as expected.
- [x] Chords are not active outside of `/project/<ref>/auth/*` and do
not trigger while typing in inputs (where `ignoreInputs` applies).

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

* **New Features**
* Global keyboard shortcuts for Auth pages: navigate auth sections,
focus/search inputs, reset filters, and open "Add" flows (providers,
OAuth apps, hooks, URLs, policies).
* "Add" controls in lists respond to shortcuts and show appropriate
disabled/tooltip states when unavailable.
* Product menu and shortcuts reference now include an "Auth Navigation"
section and per-item shortcut hints.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
2026-05-08 07:13:25 -06:00
Vaibhav df54aa1dc7 fix: docs links (#45712) 2026-05-08 13:38:25 +01:00
Joshen Lim 94851d1f8f Add assistant CTA for query errors in RLS tester (#45628)
## Context

Adding an "Ask Assistant" CTA in the RLS tester if the query executed
returns an error
<img width="618" height="375" alt="image"
src="https://github.com/user-attachments/assets/8b0a5069-3ec5-44aa-aa0b-f1cd8041960d"
/>

Which will open the Assistant panel with the following prompt (attaches
the query as well)
<img width="427" height="281" alt="image"
src="https://github.com/user-attachments/assets/16debd7b-9447-4b84-bef5-05debd0062ee"
/>

Theres a chance that the error might be just from the query and not
related to the policy hence the last sentence in the prompt


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

* **New Features**
* Integrated AI assistant into the RLS tester so users can open the
assistant prefilled with a debug prompt and relevant SQL to troubleshoot
policy issues.
* Added an "Ask Assistant" action on execution error messages to quickly
start guided debugging.
* Streamlined error display to prioritize parse errors, then client-code
parse errors, then execution errors for clearer diagnostics.

* **Chores**
* Added telemetry source identifier for the RLS tester to track
assistant usage.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-08 18:50:48 +08:00
Joshen Lim 51b45ec715 Add project region info in settings and vector buckets + make region clickable in home page instance config (#45665)
## Context

Resolves FE-2985

As per PR title

- Add project region info in project settings page for convenience
<img width="722" height="375" alt="image"
src="https://github.com/user-attachments/assets/b32e80ed-42bd-4b12-b9b4-a3e696646335"
/>

- Add project region info in vector buckets empty state
<img width="1110" height="215" alt="image"
src="https://github.com/user-attachments/assets/60bfde97-c3e3-4c10-8b86-98ecd0437ad5"
/>

- Make DB region copyable by clicking in instance config chart on home
page
<img width="419" height="298" alt="image"
src="https://github.com/user-attachments/assets/269b9517-d0eb-42b9-9648-386c59d53842"
/>



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

* **New Features**
* Project region is now shown as a read-only field with a descriptive
region label in Settings.
* Region identifiers are clickable to copy to clipboard, with a “Click
to copy” tooltip and success toast.
* Storage/empty-state messaging updated to show clearer, region-specific
text and tooltip details.
  * Replica creation time now uses an enhanced timestamp display.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-08 18:33:45 +08:00
Alaister Young 7cc8f1d1fc fix(studio): rewrite UMD AMD-check via Vite transform plugin
\`config.define\` doesn't reach pre-bundled deps in
\`node_modules/.vite/deps/*.js\`, and threading the same substitution
through \`optimizeDeps.rolldownOptions.define\` had no observable effect
either (verified: \`define.amd\` was still present in the prebundled
papaparse.js after a clean \`rm -rf .vite/deps\` + restart). Vite 8's
Rolldown-based optimizer either doesn't honour member-expression
define keys at the prebundle stage, or strips them somewhere along
the way.

New \`umdAmdShortCircuit()\` plugin runs as a \`transform\` hook on every
served file. It scans for the UMD AMD detection pattern (both
unminified \`typeof define === 'function' && define.amd\` and minified
\`"function" == typeof define && define.amd\` forms) and replaces the
expression with \`false\`. Vite's plugin pipeline runs transforms on
prebundled deps when they're served, so this catches the dev path
that \`config.define\` misses.

Skips \`monaco-editor/min/vs/loader\` defensively in case it ever lands
in the graph — Monaco's AMD loader legitimately needs to register
itself as AMD.

Dropped the redundant \`optimizeDeps.rolldownOptions.define\` (the
plugin supersedes it for all paths).

User should clear \`.vite/deps\` once after pulling
(\`rm -rf apps/studio/node_modules/.vite/deps\`) so the next dev start
re-prebundles cleanly.
2026-05-08 18:26:57 +08:00
Alaister Young 6d62ac6cdb fix(studio): also apply define substitutions to optimizeDeps prebundling
Vite's top-level \`config.define\` only substitutes files that go through
Vite's transform pipeline. Pre-bundled deps (\`node_modules/.vite/deps/*\`)
are processed by Vite's optimizer (esbuild in older Vite, Rolldown in
Vite 8) with its OWN separate define config — so our \`'define.amd':
'false'\` and \`global: 'globalThis'\` substitutions weren't reaching them.

Surfaced concretely on /functions/[slug]/invocations: papaparse is
imported transitively, gets pre-bundled into
\`node_modules/.vite/deps/papaparse.js\`, and that pre-bundled output
still contained the literal \`define.amd\` check. With Monaco's CDN
loader having installed \`window.define\` first, papaparse's UMD wrapper
hit the AMD branch and called an anonymous \`define([], t)\` that Monaco
rejected — same root cause as the original prod-build error, but in
the dev-mode prebundle path.

Extracted \`sharedDefines\` ({ global, define.amd }) and threaded it
through both:
- \`config.define\` (Vite's app-source transform)
- \`optimizeDeps.rolldownOptions.define\` (Vite 8's prebundling — note
  \`esbuildOptions\` is deprecated in v8 in favour of
  \`rolldownOptions\` since Vite 8 uses Rolldown for the optimizer).

\`process.env.NEXT_PUBLIC_*\` substitutions stay in \`config.define\`
only — they're for app source, not deps.

After pulling: clear the stale prebundle once (\`rm -rf
apps/studio/node_modules/.vite/deps\` or run \`vite dev --force\`) so it
re-prebundles with the new defines.
2026-05-08 18:19:24 +08:00
Alaister Young 81f39e4d32 fix(studio): scan whole match chain for skipFunctionsLayout flag
\`skipFunctionsLayout\` is set on the \`$functionSlug\` sub-shell's
staticData, not on the actual leaf (which only carries
\`edgeFunctionDetailsTitle\`). The shell was reading
\`matches[matches.length - 1]\` only, missed the flag, and wrapped in
EdgeFunctionsLayout — then the sub-shell's EdgeFunctionDetailsLayout
wrapped EdgeFunctionsLayout *internally* on top of that. User saw a
duplicated sidebar on every \`/functions/\$functionSlug/*\` route.

Fix: scan all matches with \`.some()\` instead. If any match in the
chain (sub-shell included) sets the flag, skip the wrap.

The \`title\` field stays leaf-only — it's only set on top-level leaves
(functions/index, new, secrets) where leaf == match[length-1].
2026-05-08 18:15:05 +08:00
Alaister Young 64d7fd1743 feat(studio): land /functions/\$functionSlug sub-shell + 5 leaves (stage 2)
routes/project/\$ref/functions/\$functionSlug.tsx: sub-shell that
provides <EdgeFunctionDetailsLayout title={...}>. Sets
skipFunctionsLayout: true on its own staticData so the parent
functions.tsx shell doesn't wrap with <EdgeFunctionsLayout> —
EdgeFunctionDetailsLayout already does that internally.

5 Path-A re-exports: index, code, details, invocations, logs. Each
sets edgeFunctionDetailsTitle in staticData (Overview, Code, Settings,
Invocations, Logs respectively) which the sub-shell reads via
useMatches({ select }).

This finishes the entire /functions/* product (3 top-level + sub-shell
+ 5 slug leaves).
2026-05-08 18:12:40 +08:00
Alaister Young ae082be60b feat(studio): land EdgeFunctionsLayout shell + 3 top-level leaves (stage 1)
routes/project/$ref/functions.tsx: shell wrapping EdgeFunctionsLayout.
Reads `functionsLayoutTitle` from leaf staticData and honours a
`skipFunctionsLayout: true` opt-out for the $functionSlug subtree (whose
EdgeFunctionDetailsLayout already wraps in EdgeFunctionsLayout
internally — same skip pattern as auth.tsx).

3 top-level leaves:
- functions/new: simple Path-A re-export, title 'New'.
- functions/index, functions/secrets: each had inline getLayout
  wrappers (PageHeader + actions). Hoisted to top-level exports
  (`EdgeFunctionsIndexPageWrapper`, `SecretsPageWrapper`) so the route
  files can re-use them — same pattern as branches/index. getLayout
  on each page now uses the exported wrapper too, so both runtimes
  render identical layout.

Stage 2 ($functionSlug sub-shell + 5 leaves) follows.
2026-05-08 18:11:23 +08:00
Alaister Young 7b4658e644 feat(studio): land BranchLayout shell + 2 leaves
routes/project/$ref/branches.tsx renders BranchLayout only — each leaf
keeps its own PageLayout because the title + primary/secondary actions
differ between Branches and Merge Requests, and the actions use hooks
(useAppStateSnapshot, useAsyncCheckPermissions) so they can't be moved
to staticData.

To avoid duplicating the wrapper logic in route files, the page-side
wrappers are hoisted/exported:
- pages/.../branches/index.tsx: \`BranchesPageWrapper\` was inline inside
  getLayout; lifted to a top-level \`export const\` taking children, and
  getLayout now uses it via \`<BranchesPageWrapper>{page}</BranchesPageWrapper>\`.
  Both runtimes still see identical layout.
- pages/.../branches/merge-requests.tsx: \`MergeRequestsPageWrapper\` was
  already top-level — just added \`export\`.

The route files import \`Page, { PageWrapper }\` from each page and render
\`<PageWrapper><Page/></PageWrapper>\`.

Migration doc updated with the BranchLayout-only delta.
2026-05-08 18:06:43 +08:00
Alaister Young 6c2dd78f45 feat(studio): land RealtimeLayout shell + 3 leaves
routes/project/$ref/realtime.tsx: RealtimeLayout sibling-file shell,
reads realtimeLayoutTitle from leaf staticData via useMatches({ select }).

3 Path-A re-exports: inspector, policies, settings. Each carries the
title in staticData.
2026-05-08 18:03:22 +08:00
Alaister Young 6215e73e49 feat(studio): land SQL Editor shell + 4 leaves
routes/project/$ref/sql.tsx renders EditorBaseLayout + SQLEditorLayout
with the props all four leaves share verbatim in their pages-router
getLayout (productMenu=SQLEditorMenu, product="SQL Editor"). Twin of
routes/project/$ref/editor.tsx. DefaultLayout is provided by the
parent project shell.

4 Path-A re-exports under the new shell: sql/index, sql/$id,
sql/templates, sql/quickstarts. None need staticData overrides — every
leaf passes the same props in Next.

EditorBaseLayout wraps in ProjectLayoutWithAuth; SQLEditorLayout adds
its own withAuth HOC but no extra ProjectLayout — same shape as the
table editor (auth check runs twice but no double render).
2026-05-08 18:00:43 +08:00
Alaister Young f7d9130c70 fix(studio): strip basePath from to-prop in next/link shim
TanStack's \`to\` prop is **basepath-relative**: with
\`basepath: '/dashboard'\`, \`to: '/foo'\` builds the href \`/dashboard/foo\`.
Next's \`href\` contract is the **full URL from app root including
basePath**, and studio code (e.g. \`buildTableEditorUrl\`) pre-prefixes
BASE_PATH into the href: \`new URL(\`\${BASE_PATH}/project/.../editor/...\`,
location.origin)\`.

After the start-plugin basepath fix (1cc0eff44a), TanStack now correctly
prepends the configured basepath when building hrefs — but our shim was
still forwarding the BASE_PATH-prefixed pathname as \`to\`. Result:
\`/dashboard\` + \`/dashboard/project/...\` → \`/dashboard/dashboard/project/...\`.

splitInternalUrl now strips a leading basePath segment so what we hand
TanStack is always basepath-relative. Match the basePath exactly or as
a path-segment prefix — don't strip coincidental matches like
\`/dashboard-other\`.

Reads NEXT_PUBLIC_BASE_PATH directly from process.env, inlined at build
time via Vite's \`define\` (must stay in sync with vite.base and
\`tanstackStart({ router: { basepath } })\`).
2026-05-08 17:57:28 +08:00
Alaister Young 4b2d7335ac chore(studio): bump dev heap to 8GB + bump vite/tanstack ecosystem
Heap bump: \`NODE_OPTIONS=--max-old-space-size=8192\` on the \`dev\`
script. Vite 8 + Rolldown (RC) + studio's dep graph (Monaco, GraphiQL,
ReactFlow, ai-sdk family, lodash inlined for SSR) was tipping over
Node's default 4GB ceiling on long dev sessions. Build still uses the
default — only dev needs the headroom.

Versions:
- vite: 8.0.8 → 8.0.10 (catalog)
- rolldown (transitive via vite): 1.0.0-rc.15 → 1.0.0-rc.17. Note:
  rolldown 1.0.0 stable shipped on npm, but Vite 8.0.10 still pins to
  rc.17. Stable rolldown will arrive in a future vite release.
- @tanstack/react-router: ^1.168.10 → ^1.169.1
- @tanstack/react-start: ^1.167.16 → ^1.167.63
- @tanstack/react-router-devtools: ^1.166.11 → ^1.166.13
- @tanstack/react-router-ssr-query: ^1.166.10 → ^1.166.12
- @tanstack/react-virtual: ^3.13.12 → ^3.13.24

Build verified green after the bump.
2026-05-08 17:49:45 +08:00
Alaister Young 1cc0eff44a fix(studio): pass router.basepath explicitly to tanstackStart()
The TanStack Start vite plugin's \`deriveRouterBasepath\` (planning.js:14
in @tanstack/start-plugin-core) only short-circuits when an explicit
\`router.basepath\` is configured. When omitted (our previous setup), it
derives the basepath from Vite's \`publicBase\` and strips both leading
and trailing slashes via \`opts.publicBase.replace(/^\\/|\\/$/g, "")\`.

That stripped value (\`/dashboard\` → \`dashboard\`) then propagates into
the runtime router and shows up in \`useRouter().basePath\`, breaking
\`\${BASE_PATH}/img/...\` style templates by producing relative URLs.

Passing \`router: { basepath }\` explicitly when NEXT_PUBLIC_BASE_PATH is
set keeps the value as-is. Mirrors what Next does with a single
\`basePath\` knob in next.config.ts.

The shim's \`toNextBasePath()\` stays — it still handles TanStack's
internal \`'/'\` default for the unset case (when no basepath is
configured at all) and trailing-slash edge cases that the start plugin
won't help with.
2026-05-08 17:41:31 +08:00
Alaister Young 81ddb37a41 fix(studio): normalise basePath in next/router shim to match Next contract
Builds on the manual leading-slash fix (41f75eb993). Two cases were
still off vs Next's pages-router contract:

  Next                              Our shim (before)
  - undefined / unset → ''          - '/' (TanStack's default)
  - '/dashboard'      → '/dashboard'  - '/dashboard'           ✓
  - 'dashboard'       → '/dashboard'  - 'dashboard' (broken)   ← manual fix
  - '/dashboard/'     → '/dashboard'  - '/dashboard/'          ✗

The '/' case was the silent dev-mode bug: studio code does
`${router.basePath}/img/foo.svg` in ~8 places. With basePath='/' that
becomes `//img/foo.svg`, a protocol-relative URL the browser tries to
resolve as `https://img/foo.svg`. Returning '' (matching Next) makes
it `/img/foo.svg` — correct absolute path.

Extracted a `toNextBasePath()` helper so the rules are explicit:
  - falsy or '/'              → ''
  - missing leading slash     → prepend '/'
  - trailing slash            → strip
2026-05-08 17:28:59 +08:00
Alaister Young ba95ce7811 fix(studio): short-circuit papaparse's UMD AMD branch via Vite define
Monaco's CDN-loaded loader.js installs an AMD-style \`window.define\` at
runtime. When a chunk containing papaparse evaluates after Monaco has
loaded, papaparse's UMD wrapper (\`typeof define === "function" &&
define.amd\`) hits the AMD branch and calls an anonymous
\`define([], t)\`. Monaco's loader queue then throws "Can only have one
anonymous define call per script file" and the page errors out.

Surfaces in prod builds specifically when navigating from /projects
into a project — that chunk-evaluation order lets Monaco's loader
register first. Direct loads of /project/.../editor happen to load
papaparse first and dodge the conflict.

Substituting the bare identifier \`define.amd\` with \`false\` at Vite
build time forces papaparse down the non-AMD branch in our bundle
(verified in dist: only the CJS / global paths remain). Monaco's
loader.js runs from a CDN script tag and isn't in our bundle, so its
own \`define.amd = true\` write isn't touched.
2026-05-08 17:21:17 +08:00
Alaister Young 41f75eb993 fix basePath prefix 2026-05-08 17:16:37 +08:00