`spawnSync` was wedging the dev path — `vite dev` would print "ready"
then exit ~1s later, taking turbo down with it. Node's synchronous
spawn blocks the event loop and doesn't pipe stdin to the child the
way an interactive dev server expects, so vite's stdin watcher saw EOF
and shut down. Async `spawn` with stdio inheritance keeps the child
interactive, and a small signal-forwarding bridge passes Ctrl-C and
friends through so killing the dispatcher still kills vite.
`build` and `start` continue to work for the same reason — they were
short-lived enough that the spawnSync flaw never showed up.
Switching from `node --env-file-if-exists=.env.local` to a hand-rolled
one-key reader. The previous shape loaded *all* of .env.local into the
parent's process.env before spawning the child, which broke e2e:
`scripts/serve.js:50` has a "don't clobber shell-set vars" guard that
treats anything pre-set in process.env as authoritative, and it can't
distinguish "really set by the shell" from "preloaded by --env-file".
So .env.test's `NEXT_PUBLIC_IS_PLATFORM=false` (the whole point of
scripts/generateLocalEnv.js) was silently overridden by .env.local's
`true`, the studio booted in platform mode, and every e2e test
auth-redirected.
The dispatcher only needs one var (STUDIO_FRAMEWORK) to pick a script.
The downstream tools (vite for build/dev, scripts/serve.js for start)
load `.env` files themselves with the correct precedence.
A bunch of master changes landed during the merge that needed
follow-ups on the TanStack side:
- Pin @tanstack/react-query to ~5.83.0 (and devtools to ~5.90.2)
in apps/studio and apps/ui-library. A previous master merge had
bumped these to ^5.100.10, which changed mutation onSuccess/onError
to require a 4th MutationFunctionContext arg and broke every studio
mutation hook still using the 3-arg shape (~570 call sites).
- Cast WebCrypto inputs to BufferSource in lib/role-impersonation.ts,
lib/ai/util.ts, lib/telemetry.tsx — TS6's DOM lib tightened
Uint8Array's generic so encoder.encode() no longer matches BufferSource
without a hint.
- compat/next/script.tsx: omit `onLoad`/`onError` from the React script
attrs we extend so our DOM-flavoured callback signatures don't clash
with React's SyntheticEvent handlers.
- compat/next/link.tsx + compat/next/navigation.ts: TanStack Router
type tightening — cast `search` and `{strict: false}` since the new
ParamsReducerFn / UseParamsOptions shapes don't fit the Next-shaped
arguments we pass through.
- router.tsx: cast the QueryClient handed to setupRouterSsrQueryIntegration.
react-router-ssr-query pulls in query-core@5.100 as a peer; we pin
react-query to 5.83. The runtime class is identical, but TS treats the
two as nominally distinct because of #private fields.
- Mirror master's page-shape changes on the route shells: drop
dehydratedState passthroughs for pages that no longer accept it
(functions/code, functions/new, integrations/github/authorize,
org.[_], project.[_]); add them back via the wrapper pattern for
pages that do still require it (redeem, aws-marketplace-onboarding,
sql/examples, stripe/projects/login).
- routes/__root.tsx: rename unused `info` to `_info` to satisfy
noUnusedParameters.
- packages/ui AnimatedCounter / Space / Typography: drop the unused
`import React from 'react'` (TS6 noUnusedLocals).
- scripts/ratchet-eslint-rules.ts: bump child_process maxBuffer from
32MB to 128MB so local runs don't truncate the ESLint JSON payload.
The top-level dev/build/start scripts now run scripts/dispatch.js, which
loads .env.local via node --env-file-if-exists and execs either the
:next or :tanstack variant based on STUDIO_FRAMEWORK. Locally the env
var lives in apps/studio/.env.local (gitignored) so the developer's
machine opts into TanStack; Vercel's Next.js prod project leaves it
unset and gets the next path. Adds :tanstack variants alongside the
existing :next ones for explicit selection.
`toWebRequest` always called `init.body = Readable.toWeb(req)` for any
non-GET/HEAD method. For requests where Node has no body to deliver
(e.g. a POST with `Content-Length: 0`), this hands undici an
already-consumed stream and `new Request(...)` throws
TypeError: Response body object should not be disturbed or locked
That bubbled up as occasional 500s during e2e runs.
Gate the body assignment on Content-Length > 0 (or Transfer-Encoding:
chunked), matching what the HTTP semantics actually allow.
`for await (chunk of response.body)` works for simple responses but can
leave the web ReadableStream in a "disturbed/locked" state when the
TanStack Start handler peeks at the body internally, surfacing on the
next request as
TypeError: Response body object should not be disturbed or locked
Switch to `Readable.fromWeb(response.body).pipe(res)` so the stream is
consumed via Node's stream machinery with backpressure and proper
cleanup. Resolves the Promise on `res.close`/`finish` and propagates
errors from either end.
Previous setup ran the studio under `vite preview` and signalled e2e
mode via `NODE_ENV=test`. That broke twice on this branch:
1. `NODE_ENV=test` in the shell overrides Vite's default
`NODE_ENV=production` for `vite build`, which makes
`@vitejs/plugin-react` emit the dev JSX runtime (`jsxDEV`). The
production SSR bundle doesn't have `jsxDEV` available, so every SSR
request crashed with `TypeError: jsxDEV is not a function`.
2. `vite preview` is a static SPA preview; it can't reuse the
`fetch`-handler shape that `apps/studio/api/server.js` exposes to
Vercel. Self-hosted prod needs its own HTTP listener for the same
handler.
Changes:
- Swap `NODE_ENV=test` for `MODE=test` end-to-end. `vite build --mode
test` keeps `NODE_ENV=production` automatically (per Vite docs), so
the React plugin stays on the prod JSX runtime and TanStack Start
bakes the right `NODE_ENV` into the SSR bundle. `.env.test` overrides
load through the standard `loadEnv(mode, ...)` order, so the
developer's `.env.local` no longer leaks `NEXT_PUBLIC_IS_PLATFORM=true`
into e2e builds.
- Explicitly set `NEXT_PUBLIC_IS_PLATFORM=false` in
`generateLocalEnv.js` so `.env.test` (which loads after `.env.local`)
wins regardless of what a developer has set locally.
- Add `apps/studio/scripts/serve.js`: a small zero-dep Node HTTP
adapter that loads env files, serves `dist/client/*` statics with
proper cache headers, and forwards everything else to the
`fetch`-handler exported by `dist/server/server.js` — the same
handler `api/server.js` hands to Vercel. `pnpm start` runs this;
`pnpm preview` keeps the old `vite preview` flow as a debug
escape-hatch.
- Add `dist/**` to studio's turbo outputs so cached builds restore
the Vite output (not just the legacy `.next/**`).
- Declare `MODE`, `PORT` in turbo env so cache invalidates correctly
when switching between test and production builds.
Proposed mitigation, the obvious tradeoff is that clearing the cache
will make compilation slower on subsequent dev server starts, but more
consistent.
Various people have been observing `next-server` use up to ~34 GB
memory. I've observed 12.59 GB memory, with ~1.5k `postcss` processes:
```
ps aux | grep postcss | grep -v grep | wc -l
1526
```
Going down to 3 `postcss` process and 4.71 GB memory after clearing
cache:
```
ps aux | grep postcss | grep -v grep | wc -l
3
```
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Development infrastructure: adds an automated pre-development step
that clears the local dev cache before starting the development server
by introducing a new lifecycle hook and supporting cleanup script;
purely maintenance-oriented with no user-facing changes or functional
impact.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
* chore: add eslint ratchet script
* chore: add eslint ratchet action
* refactor(ratchet script): convert to typescript
* ci(ratchet script): add --decrease-baselines flag
Allows us to decrease the baselines on schedule as we fix warnings
* ci(ratchet): add action to decrease baseline if possible every week
* chore(eslint): fix exhaustive-deps error
* docs(internal): improve docs for eslint ratchet script
* chore(ratchet): add new ratchet rules
Add:
- import/no-anonymous-default-export
- @tanstack/query/exhaustive-deps
- @tanstack/query/no-deprecated-options
Not adding `no-restricted-exports` even though we have many violations
because we first need to reconfigure it (if possible) to ignore those
files where Next.js requires a default export.
* Update Supabase docs URLs to use env variable
Co-authored-by: a <a@alaisteryoung.com>
* Refactor: Use DOCS_URL constant for documentation links
This change centralizes documentation links using a new DOCS_URL constant, improving maintainability and consistency.
Co-authored-by: a <a@alaisteryoung.com>
* Refactor: Use DOCS_URL constant for all documentation links
This change replaces hardcoded documentation URLs with a centralized constant, improving maintainability and consistency.
Co-authored-by: a <a@alaisteryoung.com>
* replace more instances
* ci: Autofix updates from GitHub workflow
* remaining instances
* fix duplicate useRouter
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: alaister <10985857+alaister@users.noreply.github.com>
Add the ability to look up error code explanation in API Gateway logs.
Also a bunch of GraphQL-related utilities and generated types for
calling the Content API.
* add supabase assets url to urlImports
* rm unnecessary comment
* add download script
* clean up + jsr supabasejs script
* rm unused jsr-url const
* Exclude the *.ts files in public folder from tsconfig.
* Add the base path when fetching the type definitions.
---------
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>