Commit Graph
4919 Commits
Author SHA1 Message Date
Alaister Young aedc46c8ad fix(studio): export vercel.ts config as named 'config' not default
Per the @vercel/config docs, vercel.ts must expose a named `config`
export for Vercel's build pipeline to pick it up. The default export
was compiling to a shape Vercel rejected with a misleading
"rewrites[0] missing required property source" error.
2026-04-22 01:25:02 +08:00
Alaister Young a8f0923b28 chore(studio): route /api/* and /_serverFn/* to Vercel function in vercel.ts 2026-04-22 01:19:14 +08:00
Alaister Young 386f525fd8 chore(studio): swap vercel.json for vercel.ts, apply base path to rewrites
Vercel's TypeScript config lets us read NEXT_PUBLIC_BASE_PATH at build
time and prepend it to the SPA rewrites. Vite's base only changes asset
URLs, not on-disk paths — without this, `/basepath/assets/*` 404s and
falls through to the shell.
2026-04-22 01:17:14 +08:00
Alaister Young 89674fea14 fix(studio): inline react-use for SSR to avoid Vercel CJS interop error 2026-04-22 01:04:52 +08:00
Alaister Young 0131217549 chore(studio): drop Nitro references from comments 2026-04-22 01:03:30 +08:00
Alaister Young 59d0f854de full spa 2026-04-22 00:56:01 +08:00
Alaister Young 30940c86ba no idea 2026-04-22 00:04:51 +08:00
Alaister Young 8a28471cbe testing 2026-04-21 23:53:28 +08:00
Alaister Young 6950c8a703 more routes 2026-04-21 23:48:02 +08:00
Alaister Young f34b0a913f account for basepath 2026-04-21 23:40:07 +08:00
Alaister Young 6e67210ed2 update assets path 2026-04-21 23:34:01 +08:00
Alaister Young 137afab02e try patching the vercel config 2026-04-21 23:28:48 +08:00
Alaister Young 652c6c52f3 try vercel routes overrides 2026-04-21 23:23:51 +08:00
Alaister Young ba40361f69 chore(studio): update TanStack migration checklist 2026-04-21 22:47:23 +08:00
Alaister Young 183e6b9106 spa mode 2026-04-21 22:34:53 +08:00
Alaister Young 0d0ed5d709 chore(studio): port root-level standalone pages to TanStack 2026-04-21 22:34:23 +08:00
Alaister Young 3a66c8b2ec chore(studio): port /org/[slug] subtree to TanStack 2026-04-21 22:28:47 +08:00
Alaister Young c916ab4143 chore(studio): port /account subtree to TanStack 2026-04-21 22:23:56 +08:00
Alaister Young f1e08b5487 chore(studio): port /org index route to TanStack 2026-04-21 21:14:17 +08:00
Alaister Young 34e3ef939d vercel env vars 2026-04-21 21:04:41 +08:00
Alaister Young 7ab98cf62d log public env vars 2026-04-21 20:51:35 +08:00
Alaister Young f02485b1d1 chore(studio): support NEXT_PUBLIC_BASE_PATH and port / redirect
Wire Vite `base`, Nitro `baseURL`, and the TanStack router `basepath` off
the same `NEXT_PUBLIC_BASE_PATH` env var so the prefix stays in sync (all
three layers are required — there's no single knob in TanStack Start).
Defaults are unchanged when the var is empty.

Also replace the `/` placeholder with the redirect rules that used to live
in `next.config.ts`'s `redirects()`: platform → `/org` (or
`/new/new-project` when deep-linked with `?next=new-project`), self-hosted
→ `/project/default`. Kept as a route (not a Nitro `routeRule`) so it
works in `vite dev` and can branch on the query param.
2026-04-21 20:39:35 +08:00
Alaister Young 4c7863a5ca fix(studio): defer self-hosted admin client construction
Thirteen self-hosted-only API routes under `pages/api/platform/{auth,
storage}/**` constructed a `createClient(process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_KEY!)` at module scope. On Next.js each
route was its own serverless function, so this only ran when the route
was hit. Under TanStack Start + Nitro the whole API surface is packed
into a single handler, so every request — including page renders —
evaluates every API route's module. On the platform build these env
vars intentionally aren't set (the routes only run on self-hosted), so
module evaluation hit `validateSupabaseUrl` and crashed every request
with a 500.

Introduces `selfHostedSupabaseAdmin`, a `SupabaseClient`-shaped Proxy
that constructs the real client lazily on first property access. Call
sites (`supabase.storage.getBucket(…)`) stay byte-identical; the only
per-file diff is the import.
2026-04-21 20:27:32 +08:00
Alaister Young f066597405 chore(studio): add vercel.json to disable Next framework detection
Vercel's dashboard framework preset is still set to "Next.js" from the
old pipeline, which triggers `@vercel/next`'s post-build validation and
fails because our build now emits `.vercel/output/` (Nitro's Vercel
preset, Build Output API v3) instead of `.next/routes-manifest.json`.

Setting `"framework": null` tells Vercel to skip framework-specific
handling and trust the Build Output API files Nitro writes directly.
2026-04-21 20:09:28 +08:00
Alaister Young a49e29a83f chore(studio): wire Nitro for Vercel-ready build
Adds the `nitro/vite` plugin so `vite build` produces a `.output/`
directory Vercel can pick up via the Build Output API. Along the way,
two SSR-prerender blockers had to be resolved:

- `@graphiql/react` transitively loads a codemirror addon that touches
  `document` at module-evaluation time, which crashes Nitro's prerender
  (it boots a real Node server and fetches `/`). Added an SSR-only
  Vite plugin that swaps `components/interfaces/GraphQL/GraphiQL.tsx`
  for a no-op default export — stubbing the single internal consumer
  is simpler than matching graphiql's 30+ named exports to satisfy
  Rolldown's static analysis, and no SSR-reachable route renders it.
- `tslib`'s Node ESM entry is a CJS-interop wrapper (`modules/index.js`
  re-exporting from the UMD `tslib.js`). Rolldown inlines the UMD body
  but flattens its IIFE, so `__extends` ends up declared but never
  assigned — crashing any configcat-common / AWS SDK code path that
  uses it. Force Nitro to prefer the `module` export condition so it
  picks up the pure-ESM `tslib.es6.mjs`, mark it as `noExternals` so
  the external-trace copy pass can't reintroduce the CJS wrapper at
  runtime, and inline it in Vite's SSR bundle for the same reason.

Also updates package scripts to use Vite as the primary build/dev/start
commands and preserves the Next.js equivalents as `*:next` so the old
pipeline keeps working during the migration. `.output/` is gitignored.
2026-04-21 20:05:33 +08:00
Alaister Young d12583d014 chore(studio): port /organizations route to TanStack
Re-exports pages/organizations.tsx under routes/_app/organizations.tsx.
Page default already applies withAuth; PageLayout wraps the body with
the "Your Organizations" heading. Header title and hideMobileMenu flow
via route staticData through _app.tsx.
2026-04-21 19:33:42 +08:00
Alaister Young 63b98c055d chore(studio): port remaining auth pages to TanStack routes
Re-exports sign-up, sign-in-sso, sign-in-partner, sign-in-mfa,
forgot-password(-mfa), reset-password, cli/login, and the Stripe
partners login page under `routes/_auth/`. Each wrapper replicates the
page's `getLayout` treatment; pages that inline their own layout are
rendered directly. `withAuth`-wrapped default exports stay intact.

Also hardens `compat/next/link.tsx` to accept Next's `UrlObject`
(`{pathname, query, hash}`) href form — sign-in.tsx uses this to forward
`router.query` into SSO/sign-up links, and the old shim was coercing it
to "[object Object]". Anchor attrs and `replace` now spread through;
remaining Next-only props are dropped silently.
2026-04-21 19:32:02 +08:00
Alaister Young 354839c654 chore(studio): wire 404 route into TanStack root
Re-exports the Next 404 page as the router's notFoundComponent via a
thin wrapper (Next's `NextPage` type doesn't match TanStack's
`NotFoundRouteProps` directly).
2026-04-21 19:21:00 +08:00
Alaister Young 2428cfd3b5 chore(studio): shim next/server in Vite compat layer
Two App Router routes (incident-banner, incident-status) and a few
type-only uses elsewhere import from 'next/server'. The Vite
nextCompat guard was 500ing on the build. Shim exposes
NextResponse.json (the only value surface used) and a type alias
NextRequest = Request.
2026-04-21 19:14:15 +08:00
Alaister Young c58d02e29b chore(studio): port incident-banner + incident-status App Router routes
These live under apps/studio/app/api/ rather than pages/api/ and were
missed by the initial API-routes audit. Both are already Web-native
(NextResponse extends Response), so they just need direct method
re-exports with no shim.
2026-04-21 19:12:27 +08:00
Alaister Young 387e9b1385 chore(studio): migrate Next API routes to TanStack server routes
Adds `compat/next/api.ts` exposing `toWebHandler(nextHandler)`: an
adapter that builds a NextApiRequest-shaped object from a Web
`Request` (lowercased headers, parsed cookies, merged query + route
params, JSON/urlencoded body parsing) and a NextApiResponse proxy
capturing `status` / `setHeader` / `json` / `send` / `write` / `end`
/ `redirect`. Handler output is buffered then returned as a Web
`Response`. Handlers that already return a `Response` (edge-runtime
style) pass through unchanged.

Each ported route in `routes/api/**` is a 9-line re-export: import
the default export from `pages/api/...`, wrap with `toWebHandler`,
register under `server.handlers.{GET,POST,...}`. `apiWrapper` and
`apiAuthenticate` stay untouched — they run inside the shim seeing
the shaped `req`/`res`.

Coverage: 88 of the 90 `pages/api/**` handlers. The two exceptions
need bespoke rewrites and are tracked in TANSTACK_MIGRATION.md:
- `v1/projects/[ref]/functions/[slug]/body.ts` — pipes
  `fs.createReadStream` into `res`; needs a Web-stream rewrite.
- `mcp/index.ts` — the MCP SDK transport expects Node req/res; need
  to check for a Web-fetch transport option.

Also adds `query` (params + search) to the existing `next/router`
shim to unblock components like FeedbackDropdown that read
`router.query.ref`.
2026-04-21 19:04:59 +08:00
Alaister Young 7058506661 chore(studio): migrate account/me and sign-in to TanStack routes
First two pages ported under the minimum-diff Path A strategy: the
TanStack route wraps the page default-exported from pages/ rather
than rewriting the body. Layout chains provided by pathless _app /
_auth pathless routes + sibling-file layouts, reading per-leaf props
(AccountLayout title, DefaultLayout headerTitle) from route
staticData via useMatches.

Supporting fixes:
- compat/next/router: add `query` (params + search) so components
  like FeedbackDropdown that read `router.query.ref` keep working
  under the shim.
- ConnectSheet content loader: switch to `import.meta.glob` for
  Vite (the template path spans multiple directories so
  dynamic-import-vars can't analyse it), guarded with
  `import.meta.env.SSR` to keep the 37 content modules out of the
  SSR graph — they reshuffle chunks enough to surface circular-dep
  bugs in unrelated modules. Next/webpack falls through a try/catch
  to the existing `import(\`./content/\${filePath}/content\`)`.

TANSTACK_MIGRATION.md tracks per-page status during the migration.
2026-04-21 18:41:40 +08:00
Alaister Young 7b6c11ec72 chore(studio): port RouteValidationWrapper
Extends next/router shims to expose router.pathname as the route
pattern (Next pages-router semantics) rather than the resolved URL,
by converting TanStack's matched route id ($param → [param]). Also
adds push/replace/asPath to the next/router shim so consumers like
RouteValidationWrapper can keep working unchanged.
2026-04-21 17:35:51 +08:00
Alaister Young 837ac8e8f6 chore(studio): port TelemetryTagManager + dayjs plugin setup 2026-04-21 17:18:10 +08:00
Alaister Young 1ccec55b7f chore(studio): port Telemetry 2026-04-21 17:14:26 +08:00
Alaister Young 055c1e2df8 chore(studio): port MonacoThemeProvider + monaco loader config
Also adds next/legacy/image and useSearchParams shims that the build
uncovered, and bumps @radix-ui/react-visually-hidden to ^1.2.3 so
react-select's import of VISUALLY_HIDDEN_STYLES resolves at runtime.
2026-04-21 17:12:09 +08:00
Alaister Young a2ff36e58f chore(studio): port Toaster 2026-04-21 17:03:53 +08:00
Alaister Young 939c349b1e chore(studio): port UpdateBillingAddressModal 2026-04-21 17:02:55 +08:00
Alaister Young 924a9c7c31 chore(studio): port FeaturePreviewModal 2026-04-21 17:02:17 +08:00
Alaister Young 559ed67361 chore(studio): port StudioCommandMenu 2026-04-21 17:01:09 +08:00
Alaister Young 80db2c72cc chore(studio): port MainScrollContainerProvider 2026-04-21 17:00:27 +08:00
Alaister Young ef60248c57 chore(studio): port FeaturePreviewContextProvider 2026-04-21 16:59:40 +08:00
Alaister Young 6dbcc27767 chore(studio): port StudioCommandProvider + expose router.events in next shims
- Wrap Outlet with StudioCommandProvider (imported as CommandProvider,
  matching pages/_app.tsx) inside AiAssistantStateContextProvider so
  the command menu context works in the Vite build.
- Add an events adapter to both next/router and next/compat/router
  shims so workspace code that does router.events.on('routeChangeX')
  (CommandProvider, telemetry, usePreventNavigationOnUnsavedChanges,
  QueryInsightsTable, ...) doesn't crash on `.on` of undefined.
  Subscriptions proxy to TanStack Router's router.subscribe
  (routeChangeStart -> onBeforeLoad, routeChangeComplete -> onResolved)
  and .off unsubscribes by handler identity. The proxy is cached per
  router instance via a WeakMap so effect deps stay stable.
2026-04-21 16:52:56 +08:00
Alaister Young c2337e485d chore(studio): port AiAssistantStateContextProvider to TanStack root route
Wrap Outlet with AiAssistantStateContextProvider from
@/state/ai-assistant-state inside DevToolbarProvider, matching the
wrap order in pages/_app.tsx so AI assistant state is available in
the Vite build.
2026-04-21 16:45:38 +08:00
Alaister Young 853364a1de chore(studio): port DevToolbarProvider to TanStack root route
- Wrap Outlet with DevToolbarProvider from 'dev-tools' inside the
  ThemeProvider, and render <DevToolbar extraTabs={...} /> +
  <DevToolbarTrigger /> as siblings, mirroring pages/_app.tsx.
- Guard everything behind IS_DEV_TOOLBAR_ENABLED (NEXT_PUBLIC_ENVIRONMENT
  in {local, staging}) so prod bundles tree-shake the dev-only code.
- Use React.lazy + Suspense directly for ResourceWarningsTab since
  __root.tsx is new code we control — the compat shim is only for
  existing workspace code that still imports next/dynamic.
- Add the next/dynamic -> compat/next/dynamic.tsx entry to nextShims
  so any workspace file pulled transitively (e.g. common, ui-patterns)
  keeps working via the compat layer. Shim proxies to React.lazy +
  Suspense and honours the ssr: false option.
2026-04-21 16:42:56 +08:00
Alaister Young c2ec43a86c chore(studio): port ThemeProvider + useThemeSandbox to TanStack root route
- Wrap Outlet with ThemeProvider from 'common' (defaultTheme="system",
  themes: dark/light/classic-dark, enableSystem, disableTransitionOnChange)
  and call useThemeSandbox() in RootComponent, mirroring pages/_app.tsx.
- next-themes is framework-agnostic so no compat shim is needed; it's
  not a next/* import and the lib uses plain DOM + localStorage.
- Add suppressHydrationWarning on <html>. next-themes writes
  data-theme + color-scheme onto <html> from localStorage before
  hydration so the prerendered shell (which can't know the user's
  theme) necessarily differs. The flag is React's designed escape
  hatch for this exact case and is one-level-deep, so descendants
  still diff-check normally.
2026-04-21 16:36:32 +08:00
Alaister Young 15e538e38b chore(studio): port TooltipProvider to TanStack root route
Wrap Outlet with TooltipProvider (delayDuration={0}) from 'ui',
mirroring the wrapper in pages/_app.tsx so Radix tooltip primitives
get their shared context in the Vite build.
2026-04-21 16:27:27 +08:00
Alaister Young c3f65690c2 fix(studio): use favicon-128.png for the 128x128 icon link
MetaFaviconsPagesRouter references favicon-128.png (without
dimensions) for the 128x128 size but every other variant follows the
favicon-<size>.png pattern. My initial port generated the wrong href.
Track filename + sizes separately so the link points at the file that
actually ships in public/favicon.
2026-04-21 16:26:09 +08:00
Alaister Young 3d698fb0d8 chore(studio): port <Head> + favicons + fonts to TanStack root route
- Move every static meta/link from pages/_app.tsx's <Head> and
  MetaFaviconsPagesRouter into the root route's head() so TanStack
  Start emits them via HeadContent. Covers viewport, og:image,
  googlebot, msapplication-*, theme-color, 8 apple-touch-icon-
  precomposed, 7 PNG favicons, shortcut icon, manifest, and the
  IS_PLATFORM API preconnect.
- Drop next/font from the compat path: styles/fonts.css declares the
  local CustomFont via @font-face and sets --font-custom /
  --font-source-code-pro. Source Code Pro loads from Google Fonts via
  a <link> in head(). pages/_app.tsx keeps its next/font setup for
  the Next build.
- Add a small DynamicTitle effect so useCustomContent('app:title')
  can override the default "Supabase" title at runtime, mirroring
  <title>{appTitle ?? 'Supabase'}</title> in _app.tsx.
2026-04-21 16:23:37 +08:00
Alaister Young bca8a7a0cf chore(studio): inline NEXT_PUBLIC_* env vars in the Vite build
Use vite's loadEnv to read the .env hierarchy + process.env, filter to
NEXT_PUBLIC_*, and pass them to define so process.env.NEXT_PUBLIC_X is
replaced with its value at build time (matching Next.js behaviour).

Without this, every process.env.NEXT_PUBLIC_* access in the browser
bundle would be undefined since process isn't defined in browsers.
2026-04-21 16:15:11 +08:00