chore: upgrade nft-meta-data-pointer app to Next.js 16 and React 18.3 - #657
Conversation
Bumps this Token-2022 example's frontend from Next.js 13.4.4/React
18.2.0 (mid-2023) to Next.js 16.2.12/React 18.3.1, closing a
multi-year gap in a wallet-connected browser app. Stays on React 18.x
rather than 19 because @magicblock-labs/gum-react-sdk hard-pins
react: ^18.2.0 in every published release; Next 16 itself accepts
either.
Migrates .eslintrc.json to eslint.config.mjs (flat config), since
`next lint` was removed in Next 16.
The version jump surfaced several pre-existing bugs that strict
type-checking had never caught before:
- idl/extension_nft.ts hand-writes this program's Anchor IDL and used
an old schema (isOptional, embedded account structs, the
"publicKey" type literal, no address/metadata/discriminator fields)
incompatible with the already-installed @anchor-lang/core client.
Restructured to the current schema; instruction/account
discriminators are computed via sha256("global:"/"account:" + name),
matching Anchor's own algorithm, not guessed.
- utils/anchor.ts: the Program constructor no longer takes programId
positionally now that idl.address is required and used instead.
- @coral-xyz/anchor and axios were imported but never declared as
dependencies; resolved only by accident via node_modules hoisting
under Next 13's looser module resolution.
- @solana/wallet-adapter-wallets (which bundles every hardware/mobile
wallet adapter) pulls in a Ledger dependency with a broken ESM
export under Turbopack. Replaced with the standalone
@solana/wallet-adapter-phantom and -solflare packages, since those
are the only two this app actually uses.
- gum-react-sdk's createSession() second parameter changed from a
boolean to topUpLamports (a lamport amount) between the pinned
^3.0.4 range and the resolved 3.0.10.
- ChopTreeButton.tsx: one instruction call was missing required
systemProgram/tokenProgram accounts, and an NFT-authority union type
was read unsafely in two places.
Verified: `next build` passes (full typecheck + static generation),
`next dev` serves the homepage with real Chakra UI / wallet-adapter
markup in the SSR output, `eslint .` passes with 0 errors (3
pre-existing exhaustive-deps warnings left as-is). Live browser
click-through wasn't possible in this environment - worth a manual
smoke test before merging.
| const onChopClick = useCallback(async () => { | ||
| setIsLoadingSession(true); | ||
| if (!playerDataPDA || !sessionWallet?.publicKey) return; | ||
| if (!playerDataPDA || !sessionWallet?.publicKey || !sessionWallet.sessionToken) return; |
There was a problem hiding this comment.
Session loading state stays active
When the session token expires or is cleared before this handler runs, the new guard returns after setIsLoadingSession(true) without restoring the state, leaving the session chop button indefinitely loading and preventing another attempt without remounting the component.
| if (!playerDataPDA || !sessionWallet?.publicKey || !sessionWallet.sessionToken) return; | |
| if (!playerDataPDA || !sessionWallet?.publicKey || !sessionWallet.sessionToken) { | |
| setIsLoadingSession(false); | |
| return; | |
| } |
Greptile SummaryUpgrades the NFT metadata-pointer frontend toolchain and repairs compatibility with the newer Anchor client.
Confidence Score: 4/5The session-token early-return path should be fixed before merging because it can permanently leave the chop control in a loading state. The dependency and IDL migrations are internally consistent, but the changed session guard exits after enabling loading without restoring it when the token disappears. Files Needing Attention: tokens/token-2022/nft-meta-data-pointer/anchor-example/app/components/ChopTreeButton.tsx Important Files Changed
Reviews (1): Last reviewed commit: "chore: upgrade nft-meta-data-pointer app..." | Re-trigger Greptile |
Summary
This Token-2022 example's frontend was on Next.js 13.4.4 / React 18.2.0 (mid-2023) — the only browser app in this repo, and the one place where dependency staleness is a security question (wallet-connected) rather than pure hygiene. This PR brings it to Next.js 16.2.12 / React 18.3.1.
Stays on React 18.x rather than 19:
@magicblock-labs/gum-react-sdk(used for the session-key feature) hard-pinsreact: ^18.2.0in every published release up to latest (3.0.10), with no React 19 support. Next.js itself doesn't force the issue — both Next 15 and 16 still acceptreact: ^18.2.0.What's in scope vs. what surfaced
The version jump itself is small. Getting
next buildto pass under it was not — Next 16's stricter type-checking and Turbopack bundling caught several pre-existing bugs that had never been exercised before. I've tried to keep those fixes minimal and mechanical rather than rewriting anything.Direct upgrade
next13.4.4 → 16.2.12,react/react-dom18.2.0 → 18.3.1eslint8.41.0 → 9.39.5,eslint-config-next→ 16.2.12.eslintrc.json→eslint.config.mjs(flat config) —next lintwas removed entirely in Next 16typescript5.0.4 → 5.9.3 (needed — several@solana/*transitive deps requiretypescript >= 5.4.0)Pre-existing bugs this surfaced
idl/extension_nft.tshand-writes this program's Anchor IDL and was in an old schema (isOptionalinstead ofoptional, account structs embedded directly instead of pointing into atypesarray,"publicKey"instead of"pubkey"as a type literal, and missing the now-requiredaddress/metadata/discriminatorfields) — incompatible with the already-installed@anchor-lang/coreclient, which silently collapsed every account's decoded type tonever. Restructured to the current schema. Instruction/account discriminators are computed viasha256("global:"|"account:" + name).slice(0, 8), matching Anchor's own algorithm exactly — not guessed — worth double-checking against the real deployed program's IDL if you have it handy.utils/anchor.ts: theProgramconstructor no longer takesprogramIdas a positional argument now thatidl.addressis required and used instead.@coral-xyz/anchorandaxioswere imported in a couple of files but never declared as dependencies — they only resolved before by accident, vianode_moduleshoisting under Next 13's looser module resolution. Now declared properly (axios) or replaced with the already-used@anchor-lang/core/@solana/web3.jsequivalents.@solana/wallet-adapter-wallets(the mega-package bundling every hardware/mobile wallet adapter) pulls in a Ledger dependency with a broken ESM export under Turbopack, crashing the build. This app only ever uses Phantom + Solflare, so swapped to the standalone@solana/wallet-adapter-phantom/@solana/wallet-adapter-solflarepackages instead of fighting the bundler over unused code.gum-react-sdk'screateSession()signature drifted between the pinned^3.0.4range and the resolved3.0.10: the 2nd parameter changed from abooleantotopUpLamports: number.ChopTreeButton.tsx: onechopTreeinstruction call was missing the requiredsystemProgram/tokenProgramaccounts (would have failed on-chain), and an NFT-authority field (typed asstring | { address: string }) was read unsafely in two places without checking which shape it was.Requesting extra scrutiny on
idl/extension_nft.ts— I computed these correctly against Anchor's known algorithm, but I don't have a way to test them against the actual deployed program (H31ofLpWqeAzF2Pg54HSPQGYifJad843tTJg8vCYVoh3) in this environment.ChopTreeButton.tsxaccount/null-safety fixes — logically sound based on the sibling code path in the same file, but not exercised against a live wallet.Test plan
next buildpasses: full TypeScript check + static generation of all routesnext devserves the homepage (GET / 200), and the SSR output contains real Chakra UI + wallet-adapter markup — the full provider tree mounts and renders without throwingeslint .passes with 0 errors (3 pre-existingexhaustive-depswarnings left as-is, unrelated to this change)