fix: guard React transition runtime APIs - #567
cursor[bot] wants to merge 1 commit into
Conversation
Co-authored-by: theg1239 <theg1239@users.noreply.github.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
examcooker | b2e8102 | Aug 30 2026, 11:06 AM |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| if (typeof ViewTransition !== "function") { | ||
| return <>{children}</>; | ||
| } |
There was a problem hiding this comment.
Function-only guard drops supported ViewTransition types
OptionalViewTransition treats every non-function ViewTransition export as unavailable. React-valid element types can be exotic objects, and the experimental React runtime exposes ViewTransition as Symbol(react.view_transition). This branch therefore returns only children even when the API is available, silently disabling the transition wrapper. Check whether the export is absent instead, and type the runtime value as a React element-type-compatible value rather than ComponentType.
Artifacts
Narrow ViewTransition guard render validation source
- Authored and executed React render validation that injects forwardRef, memo, and the experimental ViewTransition symbol into the wrapper runtime; it exercises the claimed guard failure path.
Rendered React behavior for current and proposed ViewTransition guards
- Captured output from the executed validation shows that the current guard drops forwardRef and memo wrappers and rejects the experimental ViewTransition symbol; the proposed guard preserves them.
React transition runtime import scanner output
- Captured output from the repository scanner confirms the installed stable React runtime has no ViewTransition export and no unsafe transition runtime imports.
| return usages; | ||
| } | ||
|
|
||
| const violations: string[] = []; |
There was a problem hiding this comment.
Transition scanner never runs automatically
The scanner is a standalone script: neither package.json nor the configured workflow files invoke it. The normal npm run build path proceeds from synchronization scripts to next build without executing this check, so an unsafe transition import can be introduced and deployed without the regression guard running. Add it to an npm validation script and invoke that script from the build or automated validation path.
Artifacts
Narrow automation-audit script source
- Shows the authored TypeScript audit that reads package.json and both configured CI workflow files for scanner references, ending with a nonzero result if any reference exists.
Normal build path without scanner invocation
- Captures `npm run build` from `/home/user/repo`; it runs only synchronization scripts and `next build`, never the scanner, then stops on the unrelated missing DATABASE_URL configuration.
Executed automation audit reporting no scanner wiring
- Captures the audit execution reporting zero package-script references and zero CI-workflow references to the scanner, confirming missing automation wiring.
Reference search with no configured invocation
- Captures the exact ripgrep search of package.json and both CI configuration locations; exit code 1 and empty output show no scanner reference.
Direct scanner execution succeeds
- Captures `CI=true node_modules/.bin/tsx scripts/test-react-transition-runtime-imports.ts` succeeding and reporting no unsafe React transition runtime imports, proving the standalone scanner is runnable.
| const namedImportRegex = new RegExp(`[{,]\\s*${name}\\b`); | ||
| if (namedImportRegex.test(statement)) { | ||
| matches.push(statement.replace(/\s+/g, " ").trim()); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return matches; | ||
| } | ||
|
|
||
| function stripComments(source: string) { | ||
| return source | ||
| .replace(/\/\*[\s\S]*?\*\//g, "") | ||
| .replace(/^\s*\/\/.*$/gm, ""); | ||
| } | ||
|
|
||
| function getUnsafeViewTransitionUsage(source: string) { | ||
| const usages: string[] = []; | ||
| const jsxRegex = /<\/?\s*ViewTransition\b/g; | ||
|
|
||
| for (const match of source.matchAll(jsxRegex)) { | ||
| usages.push(match[0]); | ||
| } | ||
|
|
||
| return usages; |
There was a problem hiding this comment.
Scanner misses direct React transition access
The named-import and literal <ViewTransition> patterns do not detect direct member access. Executable fixtures using React.addTransitionType?.(...), <React.ViewTransition />, an alias assigned from React.ViewTransition, and React.createElement(React.ViewTransition, ...) all passed the scanner. These forms bypass the guarded wrapper and can reintroduce the unsupported-runtime failure; use a TypeScript/JSX AST check that detects React member expressions and aliases derived from them.
Artifacts
Validation harness source for React transition scanner bypasses
- This authored TypeScript harness creates six scanned-root fixtures, invokes the real scanner, asserts expected results, and removes the fixtures; it defines the executed validation.
Baseline React transition scanner output without temporary fixtures
- The real scanner was executed before fixtures and exited 0 with no unsafe runtime imports reported, establishing the clean baseline.
React transition scanner output with direct React access fixtures
- The real scanner blocked both aliased named imports but passed all four direct React member-expression variants, confirming the bypass.
Temporary React transition scanner fixtures cleanup output
- A filesystem check after the harness run confirmed the temporary scanned-root fixture directory is absent, so the fixtures were cleaned up.
Bug and impact
Recent navigation/search/course registry changes reintroduced direct runtime imports of
addTransitionTypeandViewTransitionfromreact. The installedreact@19.2.8package exposes both asundefinedat runtime even though the canary type declarations allow them, so rendering course paper grids/page transitions or clicking search/filter/nav controls could crash user-facing routes.Root cause
Components imported experimental transition APIs directly from
reactinstead of going through a runtime feature-detection wrapper. This let TypeScript/Next compile while producing runtime calls/renders against missing exports.Fix
app/components/common/react-transition.tsxwith guardedaddReactTransitionTypeandOptionalViewTransitionhelpers.scripts/test-react-transition-runtime-imports.tsto fail future unsafe imports/raw<ViewTransition>usage outside the wrapper.Validation
CI=true corepack pnpm exec tsx scripts/test-react-transition-runtime-imports.tspasses and reportsaddTransitionType=undefined ViewTransition=undefined Activity=symbolplus no unsafe imports.node -e "const r=require('react'); console.log('addTransitionType=', typeof r.addTransitionType, 'ViewTransition=', typeof r.ViewTransition, 'Activity=', typeof r.Activity)"confirms the current runtime lacks both APIs.CI=true corepack pnpm buildcompiled successfully and finished TypeScript, then failed only during page-data collection becauseDATABASE_URLis unset in this environment.spent a lot of water and tokens to review your slop
Greptile Summary
This change moves experimental React transition access behind a compatibility wrapper and adds a scanner intended to prevent unsafe imports. Render validation showed that the wrapper drops valid non-function
ViewTransitionvalues, including the experimental symbol-based export. The scanner is not run by the configured automated checks and does not detect several directReactmember-access forms, allowing unsafe calls to bypass the intended safeguard. These issues should be resolved before merge.Confidence Score: 2/5
Not safe to merge until the transition wrapper accepts the supported runtime element type and the regression scanner is both comprehensive and automatically executed.
Three independently reproduced defects can disable intended transitions or allow unsupported React transition API usage to bypass the newly added safeguard.
Files Needing Attention: app/components/common/react-transition.tsx requires a presence-based runtime guard; scripts/test-react-transition-runtime-imports.ts requires broader detection and automated invocation from package and workflow configuration.
What T-Rex did
Comments Outside Diff (3)
General comment
typeof ViewTransition !== "function"assumes every valid React element type is callable, but React accepts exotic object types and special symbol element types.app/components/common/react-transition.tsx:23with an absence check such asif (ViewTransition === undefined), and widen the local runtime type fromReact.ComponentType<ViewTransitionProps>to a React element-type-compatible type.General comment
scripts/test-react-transition-runtime-imports.tshas no invocation inpackage.json,.github/workflows/deploy-appservice.yml, orazure-pipelines.yml. The normal build path (npm run build) runs synchronization scripts andnext build, not this scanner. Consequently, regressions the scanner is intended to catch can merge and deploy without the scanner running.test:react-transition-runtime-imports: tsx scripts/test-react-transition-runtime-imports.ts) and invoke it from the CI validation/build sequence (or a CI test job) so pull requests and deployment builds execute it.General comment
scripts/test-react-transition-runtime-imports.tsfails to report executable direct access to unsafe transition APIs:React.addTransitionType?.(...), JSX<React.ViewTransition />, an aliasedconst Transition = React.ViewTransitionrendered as<Transition />, andReact.createElement(React.ViewTransition, ...). All four fixtures were scanned fromapp/and passed unreported.<ViewTransition>JSX tag. Neither detection path recognizes member expressions, aliases originating from member expressions, orcreateElementarguments.React.addTransitionTypeandReact.ViewTransitionmember expressions, track local aliases assigned fromReact.ViewTransition, and flag JSX/createElement usages of those aliases. Retain the current named-import checks.Reviews (1): Last reviewed commit: "fix: guard React transition runtime APIs" | Re-trigger Greptile