fix(studio): catch TanStack-side typechecks up with master + TS6

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.
This commit is contained in:
Alaister Young committed 2026-05-27 22:31:27 +08:00
1 parent 251f9edafc
commit a4b6016757
27 files changed
+100 -62

No files matched your search

+6 -1
View File
@@ -238,7 +238,12 @@ function buildResponse() {
// We honour `statusCode` and `headers`; `statusMessage` is dropped
// (Fetch `Response` doesn't preserve a custom HTTP/1 reason phrase
// when running through TanStack's runtime).
;(res as unknown as { writeHead: (...args: unknown[]) => unknown }).writeHead = (
type WriteHead = (
code: number,
headersOrMessage?: string | Record<string, number | string | readonly string[]>,
maybeHeaders?: Record<string, number | string | readonly string[]>
) => unknown
;(res as unknown as { writeHead: WriteHead }).writeHead = (
code: number,
headersOrMessage?: string | Record<string, number | string | readonly string[]>,
maybeHeaders?: Record<string, number | string | readonly string[]>
+4 -2
View File
@@ -197,7 +197,8 @@ const Link = forwardRef(function Link(
<TanStackLink
// eslint-disable-next-line @typescript-eslint/no-explicit-any
to={to as any}
search={search}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
search={search as any}
hash={hash}
replace={replace}
preload={preload}
@@ -233,7 +234,8 @@ const Link = forwardRef(function Link(
<TanStackLink
// eslint-disable-next-line @typescript-eslint/no-explicit-any
to={to as any}
search={search}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
search={search as any}
hash={hash}
replace={replace}
preload={preload}
+2 -1
View File
@@ -73,7 +73,8 @@ export function useParams<
// App Router's useParams() returns a flat object of dynamic segments.
// TanStack's strict-false useParams returns the same shape merged
// across matches.
return useTanStackParams({ strict: false }) as T
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return useTanStackParams({ strict: false } as any) as T
}
// `useSelectedLayoutSegment(parallelRoute?)` returns the active leaf
+4 -2
View File
@@ -8,7 +8,10 @@ import { useEffect, useRef, type ComponentPropsWithoutRef, type ReactNode } from
type Strategy = 'beforeInteractive' | 'afterInteractive' | 'lazyOnload' | 'worker'
interface ScriptProps extends Omit<ComponentPropsWithoutRef<'script'>, 'children'> {
interface ScriptProps extends Omit<
ComponentPropsWithoutRef<'script'>,
'children' | 'onLoad' | 'onError'
> {
// Accepted-and-dropped in this shim — the browser handles network
// priority via the regular `<script>` element; we don't reorder.
strategy?: Strategy
@@ -78,7 +81,6 @@ export default function Script({
ref={ref}
onLoad={handleLoad}
onError={handleError}
dangerouslySetInnerHTML={{
__html: typeof children === 'string' ? children : '',
}}
+1 -1
View File
@@ -32,7 +32,7 @@ export async function selectWeightedKey<T extends string>(
const keys = Object.keys(weights) as T[]
const encoder = new TextEncoder()
const data = encoder.encode(input)
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
const hashBuffer = await crypto.subtle.digest('SHA-256', data as BufferSource)
// Use first 4 bytes (32 bit integer)
const hashInt = new DataView(hashBuffer).getUint32(0)
+2 -2
View File
@@ -126,7 +126,7 @@ function encodeBase64Url(data: ArrayBuffer | Uint8Array | string): string {
function genKey(rawKey: string) {
return window.crypto.subtle.importKey(
'raw',
encodeText(rawKey),
encodeText(rawKey) as BufferSource,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign', 'verify']
@@ -144,7 +144,7 @@ async function createToken(jwtPayload: object, key: string) {
await window.crypto.subtle.sign(
{ name: 'HMAC' },
await genKey(key),
encodeText(headerAndPayload)
encodeText(headerAndPayload) as BufferSource
)
)
)
+1 -1
View File
@@ -10,7 +10,7 @@ import { API_URL, IS_PLATFORM } from '@/lib/constants'
const getAnonId = async (id: string) => {
const encoder = new TextEncoder()
const data = encoder.encode(id)
const hashBuffer = await crypto.subtle.digest('SHA-256', data)
const hashBuffer = await crypto.subtle.digest('SHA-256', data as BufferSource)
const hashArray = Array.from(new Uint8Array(hashBuffer))
const base64String = btoa(hashArray.map((byte) => String.fromCharCode(byte)).join(''))
+2 -2
View File
@@ -78,8 +78,8 @@
"@supabase/supabase-js": "catalog:",
"@tanstack/react-devtools": "^0.10.3",
"@tanstack/react-hotkeys": "^0.10.0",
"@tanstack/react-query": "^5.100.10",
"@tanstack/react-query-devtools": "^5.100.10",
"@tanstack/react-query": "~5.83.0",
"@tanstack/react-query-devtools": "~5.90.2",
"@tanstack/react-router": "catalog:",
"@tanstack/react-router-devtools": "^1.166.13",
"@tanstack/react-router-ssr-query": "^1.166.12",
+6 -1
View File
@@ -28,7 +28,12 @@ export function getRouter() {
basepath: process.env.NEXT_PUBLIC_BASE_PATH || undefined,
})
setupRouterSsrQueryIntegration({ router, queryClient: context.queryClient })
// @tanstack/react-router-ssr-query@1.166.12 pulls in @tanstack/query-core@5.100
// as a peer, but our app pins react-query to 5.83. The QueryClient class is
// structurally identical between the two, but TS treats them as nominally
// distinct types because each version has its own `#private` field.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setupRouterSsrQueryIntegration({ router, queryClient: context.queryClient as any })
return router
}
+1 -1
View File
@@ -236,7 +236,7 @@ function DynamicTitle() {
return <title>{appTitle}</title>
}
const errorBoundaryHandler = (error: Error, info: ErrorInfo) => {
const errorBoundaryHandler = (error: Error, _info: ErrorInfo) => {
Sentry.withScope(function (scope) {
scope.setTag('globalErrorBoundary', true)
const eventId = Sentry.captureException(error)
@@ -8,5 +8,5 @@ export const Route = createFileRoute('/_auth/partners/stripe/projects/login')({
function StripeProjectsLogin() {
// Next page default export is already wrapped in withAuth and inlines APIAuthorizationLayout.
return <StripeProjectsLoginPage />
return <StripeProjectsLoginPage dehydratedState={undefined} />
}
@@ -3,5 +3,9 @@ import { createFileRoute } from '@tanstack/react-router'
import AwsMarketplaceOnboardingPage from '@/pages/aws-marketplace-onboarding'
export const Route = createFileRoute('/aws-marketplace-onboarding')({
component: AwsMarketplaceOnboardingPage,
component: AwsMarketplaceOnboardingRoute,
})
function AwsMarketplaceOnboardingRoute() {
return <AwsMarketplaceOnboardingPage dehydratedState={undefined} />
}
@@ -9,5 +9,5 @@ export const Route = createFileRoute('/integrations/github/authorize')({
// Placed at top-level — the Next page has no getLayout (renders bare),
// so adding AppLayout/DefaultLayout via _app would be a behaviour change.
function GitHubAuthorizeRoute() {
return <GitHubIntegrationAuthorize dehydratedState={undefined} />
return <GitHubIntegrationAuthorize />
}
+1 -1
View File
@@ -16,5 +16,5 @@ export const Route = createFileRoute('/org/_/$')({
// router-generator bug that strips the escaped `_` segment when the
// last segment isn't escaped.
function OrgWildcardSplatRoute() {
return <GenericOrganizationPage dehydratedState={undefined} />
return <GenericOrganizationPage />
}
+1 -1
View File
@@ -19,5 +19,5 @@ export const Route = createFileRoute('/org/_')({
// to `/`). The path-as-filename form keeps the last segment non-index,
// so the bug branch is skipped.
function OrgWildcardIndexRoute() {
return <GenericOrganizationPage dehydratedState={undefined} />
return <GenericOrganizationPage />
}
+1 -1
View File
@@ -16,5 +16,5 @@ export const Route = createFileRoute('/project/_/$')({
// router-generator bug that strips the escaped `_` segment when the
// last segment isn't escaped.
function ProjectWildcardSplatRoute() {
return <GenericProjectPage dehydratedState={undefined} />
return <GenericProjectPage />
}
+1 -1
View File
@@ -11,5 +11,5 @@ export const Route = createFileRoute('/project/_')({
// why this is named with the path-as-filename form rather than
// `project/[_]/index.tsx`.
function ProjectWildcardIndexRoute() {
return <GenericProjectPage dehydratedState={undefined} />
return <GenericProjectPage />
}
@@ -10,5 +10,5 @@ export const Route = createFileRoute('/project/$ref/functions/$functionSlug/code
})
function FunctionCodeRoute() {
return <CodePage dehydratedState={undefined} />
return <CodePage />
}
@@ -10,5 +10,5 @@ export const Route = createFileRoute('/project/$ref/functions/new')({
})
function FunctionsNewRoute() {
return <NewFunctionPage dehydratedState={undefined} />
return <NewFunctionPage />
}
@@ -3,5 +3,9 @@ import { createFileRoute } from '@tanstack/react-router'
import SqlExamples from '@/pages/project/[ref]/sql/examples'
export const Route = createFileRoute('/project/$ref/sql/examples')({
component: SqlExamples,
component: SqlExamplesRoute,
})
function SqlExamplesRoute() {
return <SqlExamples dehydratedState={undefined} />
}
+5 -1
View File
@@ -3,5 +3,9 @@ import { createFileRoute } from '@tanstack/react-router'
import RedeemCreditsPage from '@/pages/redeem'
export const Route = createFileRoute('/redeem')({
component: RedeemCreditsPage,
component: RedeemRoute,
})
function RedeemRoute() {
return <RedeemCreditsPage dehydratedState={undefined} />
}
+1 -1
View File
@@ -128,7 +128,7 @@ function dangerouslyRunEsLint(eslintCmd: string, eslintArgs: string): ESLintExec
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
env: process.env,
maxBuffer: 32 * 1024 * 1024, // allow large ESLint JSON payloads
maxBuffer: 128 * 1024 * 1024, // allow large ESLint JSON payloads (the studio repo regularly emits ~35MB+)
})
const stdout = typeof proc.stdout === 'string' ? proc.stdout : ''
+1 -1
View File
@@ -25,7 +25,7 @@
"@supabase/postgrest-js": "catalog:",
"@supabase/supa-mdx-lint": "0.2.6-alpha",
"@supabase/vue-blocks": "workspace:*",
"@tanstack/react-query": "^5.100.10",
"@tanstack/react-query": "~5.83.0",
"@xyflow/react": "^12.10.1",
"api-types": "workspace:*",
"axios": "^1.12.0",
@@ -1,7 +1,7 @@
'use client'
import { animate, motion, useInView, useMotionValue, useTransform } from 'framer-motion'
import React, { FC, useEffect, useRef } from 'react'
import { FC, useEffect, useRef } from 'react'
import { cn } from '../../lib/utils/cn'
@@ -1,5 +1,3 @@
import React from 'react'
// @ts-ignore
// import SpaceStyles from './Space.module.css'
@@ -1,5 +1,3 @@
import React from 'react'
import Link from './Link'
import Text from './Text'
import Title from './Title'
+45 -30
View File
@@ -367,7 +367,7 @@ importers:
version: 2.106.2
'@tanstack/react-query':
specifier: ^5.100.10
version: 5.100.10(react@19.2.6)
version: 5.100.14(react@19.2.6)
acorn:
specifier: ^8.11.3
version: 8.11.3
@@ -987,11 +987,11 @@ importers:
specifier: ^0.10.0
version: 0.10.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@tanstack/react-query':
specifier: ^5.100.10
version: 5.100.10(react@19.2.6)
specifier: ~5.83.0
version: 5.83.0(react@19.2.6)
'@tanstack/react-query-devtools':
specifier: ^5.100.10
version: 5.100.10(@tanstack/react-query@5.100.10(react@19.2.6))(react@19.2.6)
specifier: ~5.90.2
version: 5.90.2(@tanstack/react-query@5.83.0(react@19.2.6))(react@19.2.6)
'@tanstack/react-router':
specifier: 'catalog:'
version: 1.169.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
@@ -1000,7 +1000,7 @@ importers:
version: 1.166.13(@tanstack/react-router@1.169.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.169.2)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@tanstack/react-router-ssr-query':
specifier: ^1.166.12
version: 1.166.12(@tanstack/query-core@5.100.10)(@tanstack/react-query@5.100.10(react@19.2.6))(@tanstack/react-router@1.169.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.169.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
version: 1.166.12(@tanstack/query-core@5.100.14)(@tanstack/react-query@5.83.0(react@19.2.6))(@tanstack/react-router@1.169.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.169.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@tanstack/react-start':
specifier: 'catalog:'
version: 1.167.65(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.13(@types/node@22.13.14)(esbuild@0.25.2)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.20.3)(yaml@2.8.3))(webpack@5.105.4(esbuild@0.25.2))
@@ -1438,8 +1438,8 @@ importers:
specifier: workspace:*
version: link:../../blocks/vue
'@tanstack/react-query':
specifier: ^5.100.10
version: 5.100.10(react@19.2.6)
specifier: ~5.83.0
version: 5.83.0(react@19.2.6)
'@xyflow/react':
specifier: ^12.10.1
version: 12.10.1(@types/react@19.2.14)(immer@10.1.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
@@ -8051,11 +8051,14 @@ packages:
resolution: {integrity: sha512-vqH7X9nb0MTJ/O08++dB5bP9jgj4+BIPOUu/U+6myG86lDsirZSVSobpq5UQpE7nBuk62i8eIYeOhd+OMl/UrA==}
engines: {node: '>=18'}
'@tanstack/query-core@5.100.10':
resolution: {integrity: sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==}
'@tanstack/query-core@5.100.14':
resolution: {integrity: sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==}
'@tanstack/query-devtools@5.100.10':
resolution: {integrity: sha512-3DmJf25hDPus5IpVvp6ujXv6bKV2zPzI9vpbAmpJigsL/H6DPvPjmf7/Q9yVKEke//8fgeQ45abjgnLuyYxAiw==}
'@tanstack/query-core@5.83.0':
resolution: {integrity: sha512-0M8dA+amXUkyz5cVUm/B+zSk3xkQAcuXuz5/Q/LveT4ots2rBpPTZOzd7yJa2Utsf8D2Upl5KyjhHRY+9lB/XA==}
'@tanstack/query-devtools@5.90.1':
resolution: {integrity: sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==}
'@tanstack/react-devtools@0.10.5':
resolution: {integrity: sha512-orVsRJ7oAXFb7oyafQCgx9YuK44jpILh5T/ddYuxAsolNfN5DZBr5/NLrWErD7HCGIzvYzg1TZI4sPxmiKvtvA==}
@@ -8073,14 +8076,19 @@ packages:
react: '>=16.8'
react-dom: '>=16.8'
'@tanstack/react-query-devtools@5.100.10':
resolution: {integrity: sha512-zes0+o9ef5rAZXJ9f/SeaLs2nufJaeVkZkl/Or9NGrWVF41kL9Od9ED9nCwtQlgiF2VGtrzhEw5AU/igAO+aAg==}
'@tanstack/react-query-devtools@5.90.2':
resolution: {integrity: sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ==}
peerDependencies:
'@tanstack/react-query': ^5.100.10
'@tanstack/react-query': ^5.90.2
react: ^18 || ^19
'@tanstack/react-query@5.100.10':
resolution: {integrity: sha512-FLaZf2RCrA/Zgp4aiu5tG3TyasTRO7aZ99skxQpr3Hg/zXOhu6yq5FZCYQ/tRaJtM9ylnoK8tFK7PolXQadv6Q==}
'@tanstack/react-query@5.100.14':
resolution: {integrity: sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==}
peerDependencies:
react: ^18 || ^19
'@tanstack/react-query@5.83.0':
resolution: {integrity: sha512-/XGYhZ3foc5H0VM2jLSD/NyBRIOK4q9kfeml4+0x2DlL6xVuAcVEW+hTlTapAmejObg0i3eNqhkr2dT+eciwoQ==}
peerDependencies:
react: ^18 || ^19
@@ -24412,9 +24420,11 @@ snapshots:
dependencies:
'@tanstack/store': 0.11.0
'@tanstack/query-core@5.100.10': {}
'@tanstack/query-core@5.100.14': {}
'@tanstack/query-devtools@5.100.10': {}
'@tanstack/query-core@5.83.0': {}
'@tanstack/query-devtools@5.90.1': {}
'@tanstack/react-devtools@0.10.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(solid-js@1.9.12)':
dependencies:
@@ -24436,15 +24446,20 @@ snapshots:
react: 19.2.6
react-dom: 19.2.6(react@19.2.6)
'@tanstack/react-query-devtools@5.100.10(@tanstack/react-query@5.100.10(react@19.2.6))(react@19.2.6)':
'@tanstack/react-query-devtools@5.90.2(@tanstack/react-query@5.83.0(react@19.2.6))(react@19.2.6)':
dependencies:
'@tanstack/query-devtools': 5.100.10
'@tanstack/react-query': 5.100.10(react@19.2.6)
'@tanstack/query-devtools': 5.90.1
'@tanstack/react-query': 5.83.0(react@19.2.6)
react: 19.2.6
'@tanstack/react-query@5.100.10(react@19.2.6)':
'@tanstack/react-query@5.100.14(react@19.2.6)':
dependencies:
'@tanstack/query-core': 5.100.10
'@tanstack/query-core': 5.100.14
react: 19.2.6
'@tanstack/react-query@5.83.0(react@19.2.6)':
dependencies:
'@tanstack/query-core': 5.83.0
react: 19.2.6
'@tanstack/react-router-devtools@1.166.13(@tanstack/react-router@1.169.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.169.2)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
@@ -24458,12 +24473,12 @@ snapshots:
transitivePeerDependencies:
- csstype
'@tanstack/react-router-ssr-query@1.166.12(@tanstack/query-core@5.100.10)(@tanstack/react-query@5.100.10(react@19.2.6))(@tanstack/react-router@1.169.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.169.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
'@tanstack/react-router-ssr-query@1.166.12(@tanstack/query-core@5.100.14)(@tanstack/react-query@5.83.0(react@19.2.6))(@tanstack/react-router@1.169.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.169.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)':
dependencies:
'@tanstack/query-core': 5.100.10
'@tanstack/react-query': 5.100.10(react@19.2.6)
'@tanstack/query-core': 5.100.14
'@tanstack/react-query': 5.83.0(react@19.2.6)
'@tanstack/react-router': 1.169.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@tanstack/router-ssr-query-core': 1.168.0(@tanstack/query-core@5.100.10)(@tanstack/router-core@1.169.2)
'@tanstack/router-ssr-query-core': 1.168.0(@tanstack/query-core@5.100.14)(@tanstack/router-core@1.169.2)
react: 19.2.6
react-dom: 19.2.6(react@19.2.6)
transitivePeerDependencies:
@@ -24619,9 +24634,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@tanstack/router-ssr-query-core@1.168.0(@tanstack/query-core@5.100.10)(@tanstack/router-core@1.169.2)':
'@tanstack/router-ssr-query-core@1.168.0(@tanstack/query-core@5.100.14)(@tanstack/router-core@1.169.2)':
dependencies:
'@tanstack/query-core': 5.100.10
'@tanstack/query-core': 5.100.14
'@tanstack/router-core': 1.169.2
'@tanstack/router-utils@1.161.8(supports-color@8.1.1)':