Skip to content

refactor(react): move wallet integration to apps/next#102

Merged
gaboesquivel merged 12 commits intomainfrom
refactor-wallet-integration
Feb 18, 2026
Merged

refactor(react): move wallet integration to apps/next#102
gaboesquivel merged 12 commits intomainfrom
refactor-wallet-integration

Conversation

@gaboesquivel
Copy link
Copy Markdown
Member

@gaboesquivel gaboesquivel commented Feb 18, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added authentication verification hooks for web3 and wallet linking flows.
  • Documentation

    • Updated architecture guides to reflect wallet hook restructuring.
    • Clarified E2E testing now runs against local servers.
    • Updated deployment documentation for Git-based Vercel integration.
  • Refactor

    • Simplified wallet authentication verification flow.
    • Removed transaction and message signing from public wallet APIs.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 18, 2026

Warning

Rate limit exceeded

@gaboesquivel has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 10 minutes and 42 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

This PR refactors wallet-related hooks architecture by moving implementations from centralized @repo/react to app-local hooks in the Next app, introduces two new verification hooks in @repo/react, removes several wallet-related exports from the public API, restructures GitHub Actions workflows to focus on E2E testing, and enables Git-based Vercel deployments with npx pnpm commands.

Changes

Cohort / File(s) Summary
Wallet hooks relocation
apps/next/hooks/use-wallet.ts, apps/next/hooks/use-wallet-auth.ts, apps/next/hooks/use-link-wallet.ts
Moved from centralized exports to app-local implementations with updated import paths and types; useWalletAuth and useLinkWallet now use new verification hooks via mutateAsync.
App-local wallet hook tests
apps/next/hooks/use-wallet.test.tsx, apps/next/hooks/use-wallet-auth.test.tsx, apps/next/hooks/use-link-wallet.test.tsx, apps/next/hooks/use-web3-nonce.test.tsx
Added comprehensive test coverage for relocated hooks with updated mock client shapes and mock ReactApiProvider integration; simplified test assertions and added new test cases for Solana chain handling.
Wallet context and adapter types
apps/next/wallet/types.ts, apps/next/wallet/context.tsx
New local types file exporting Web3Chain and WalletAdapter interface for app-local wallet implementations.
App-local hook usage
apps/next/components/dashboard/dashboard-wallet-content.tsx, apps/next/components/login/wallet-options-view.tsx, apps/next/components/wallet-sign-in-buttons.tsx, apps/next/components/wallet-adapters-injector.tsx
Updated imports to use app-local hooks from @/hooks/ and @/wallet/ instead of @repo/react; aliased Solana useWallet to avoid conflicts.
Verification hooks (new)
packages/react/src/hooks/use-verify-web3-auth.ts, packages/react/src/hooks/use-verify-link-wallet.ts
New mutation hooks providing chain-specific verification with auth callback URL handling and session cache invalidation; replaces multi-step verification logic in app-local hooks.
Verification hook tests
packages/react/src/hooks/use-verify-web3-auth.test.tsx, packages/react/src/hooks/use-verify-link-wallet.test.tsx
Added test suites for new verification hooks covering eip155 and solana chains with mock client integration.
Removed hooks from @repo/react
packages/react/src/hooks/use-wallet.ts, packages/react/src/hooks/use-wallet-auth.ts, packages/react/src/hooks/use-wallet-sign.ts, packages/react/src/hooks/use-wallet-send-transaction.ts
Removed wallet management hooks and related test files; wallet interactions now delegated to app-local implementations and verify hooks.
Public API updates
packages/react/src/index.ts, packages/react/src/types.ts, packages/react/src/wallet/types.ts
Removed wallet hook exports and types; added useVerifyWeb3Auth and useVerifyLinkWallet exports; moved Web3Chain type to new types.ts file; removed viem dependency.
Architecture documentation
.cursor/rules/web3/wagmi.mdc, apps/docu/content/docs/architecture/authentication.mdx, apps/docu/content/docs/architecture/frontend-stack.mdx
Updated guidance and diagrams to reflect app-local hooks under @/hooks and @/wallet, new verify hooks in @repo/react, and revised component interactions.
GitHub Actions E2E workflows
.github/workflows/next-e2e.yml, .github/workflows/api-e2e.yml
New workflows focused on local E2E testing with conditional build skipping; replaced previous deploy+E2E workflows with separate E2E-only pipelines.
Removed deployment workflows
.github/workflows/next-deploy-e2e.yml, .github/workflows/api-deploy-e2e.yml, .github/workflows/docu-deploy.yml
Deleted combined deploy+E2E workflows; Vercel deployments now handled via Git integration instead of CI.
Vercel configuration
apps/next/vercel.json, apps/fastify/vercel.json, apps/docu/vercel.json
Updated build/install/dev commands to use npx pnpm wrapper; enabled Git deployments on main and develop branches.
Deployment and testing documentation
apps/docu/content/docs/deployment/vercel.mdx, apps/docu/content/docs/deployment/github-actions.mdx, apps/docu/content/docs/testing/e2e-testing.mdx, .cursor/rules/frontend/e2e-playwright.mdc, README.md
Updated guidance for Git-based Vercel deployments, local E2E testing workflows, and SKIP_BUILD environment variable usage.
Build script updates
apps/next/scripts/run-e2e-local.mjs
Added conditional build execution controlled by SKIP_BUILD environment variable.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Next Component
    participant Auth as useWalletAuth Hook
    participant Adapter as Wallet Adapter
    participant Verify as useVerifyWeb3Auth
    participant Backend as API Backend

    rect rgba(100, 150, 200, 0.5)
    Note over Client,Backend: Old Flow (Removed)
    Client->>Auth: signIn()
    Auth->>Adapter: signMessage(message)
    Adapter-->>Auth: signature
    Auth->>Backend: POST /auth/verify (direct call)
    Backend-->>Auth: verify response
    Auth-->>Client: result
    end

    rect rgba(150, 200, 100, 0.5)
    Note over Client,Backend: New Flow (With Verify Hooks)
    Client->>Auth: signIn()
    Auth->>Adapter: signMessage(message)
    Adapter-->>Auth: signature
    Auth->>Verify: mutateAsync({chain, message, signature, domain})
    Verify->>Backend: POST /auth/verify (via mutation)
    Backend-->>Verify: verify response
    Verify-->>Auth: result + session invalidation
    Auth-->>Client: result
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #89: Introduces Fastify web3 nonce and verify endpoints (/auth/web3/{chain}/nonce, /auth/web3/{chain}/verify) that directly serve the new useVerifyWeb3Auth hook's backend requirements.
  • PR #90: Implements the Fastify account link wallet verify endpoint (/account/link/wallet/verify) consumed by the new useVerifyLinkWallet hook.
  • PR #101: Modifies GitHub Actions deployment workflows in parallel, removing deploy-centric workflows and restructuring CI/CD pipeline alongside this PR's workflow changes.

Poem

🐰 Hooks once far now live right here,
Local paths make code more clear,
Verify hooks take the wheel,
Git deploys with real appeal! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main refactoring: moving wallet integration logic from the shared @repo/react package to the app-local apps/next implementation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-wallet-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/next/hooks/use-link-wallet.ts (1)

73-76: ⚠️ Potential issue | 🟡 Minor

Misleading error message when only signMessage is absent.

if (!address || !signMessage) covers two distinct missing states, but the thrown message 'No wallet address' only describes one. A caller debugging a missing signMessage (e.g., before wallet adapters are wired up) would get a confusing error.

🛠️ Proposed fix
-      if (!address || !signMessage) {
-        throw new Error('No wallet address')
-      }
+      if (!address) throw new Error('No wallet connected')
+      if (!signMessage) throw new Error('Wallet does not support message signing')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-link-wallet.ts` around lines 73 - 76, The mutationFn
currently throws a misleading generic error when either address or signMessage
is missing; update mutationFn in use-link-wallet.ts to validate each dependency
separately (check address and check signMessage) and throw distinct, descriptive
errors (e.g., "No wallet address" when address is missing and "No signMessage
function" or similar when signMessage is missing) so callers can identify which
piece is not wired up.
apps/next/hooks/use-wallet-auth.ts (1)

79-81: ⚠️ Potential issue | 🟡 Minor

Error message "No wallet address" is misleading when chain or signMessage is absent

The guard condition covers three different failure modes, but only one message is surfaced — making it hard to diagnose which field is actually missing.

🐛 Proposed fix
-      if (!address || !signMessage || !chain) {
-        throw new Error('No wallet address')
-      }
+      if (!chain) throw new Error('No wallet chain specified')
+      if (!address) throw new Error('No wallet address')
+      if (!signMessage) throw new Error('No signMessage function provided')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-wallet-auth.ts` around lines 79 - 81, The current guard
in the hook checks address, signMessage, and chain but always throws "No wallet
address", which is misleading; update the check in use-wallet-auth (the block
that evaluates address, signMessage, chain) to detect which of address,
signMessage, or chain is missing and throw or return a clear, specific error
message for each (e.g., "No wallet address", "No signMessage function", "No
chain configured") or build a combined message listing missing fields so callers
can immediately see which dependency (address, signMessage, or chain) is absent.
🧹 Nitpick comments (7)
packages/react/src/hooks/use-verify-link-wallet.ts (1)

5-5: Web3Chain imported from a sibling hook — consider a shared types module.

use-verify-link-wallet.ts imports Web3Chain from ./use-verify-web3-auth, creating a lateral dependency between two peer hooks. If use-verify-web3-auth ever changes its public surface, it could unintentionally break use-verify-link-wallet. A dedicated packages/react/src/types.ts (or packages/react/src/wallet/types.ts) would give the type a stable, purpose-built home.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/src/hooks/use-verify-link-wallet.ts` at line 5, The hook
use-verify-link-wallet.ts currently imports the Web3Chain type from a sibling
hook use-verify-web3-auth, creating a lateral dependency; extract Web3Chain into
a stable shared types module (e.g., packages/react/src/types.ts or
packages/react/src/wallet/types.ts), export the type from there, and update
use-verify-link-wallet.ts and use-verify-web3-auth to import Web3Chain from the
new types module to remove the peer-hook coupling.
apps/next/hooks/use-wallet.ts (1)

15-15: Redundant ternary — chain is already the correct index.

chain === 'eip155' ? 'eip155' : 'solana' always equals chain for a Web3Chain-typed argument. The ternary adds noise without guarding anything.

♻️ Proposed simplification
-  if (chain) return ctx.adapters[chain === 'eip155' ? 'eip155' : 'solana']
+  if (chain) return ctx.adapters[chain]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-wallet.ts` at line 15, The conditional uses a redundant
ternary when selecting an adapter: in the use-wallet hook replace the expression
ctx.adapters[chain === 'eip155' ? 'eip155' : 'solana'] with a direct lookup
using ctx.adapters[chain]; update the return path that currently reads if
(chain) return ctx.adapters[...] to simply return ctx.adapters[chain] (still
guarding for a falsy chain first) so the code uses the Web3Chain-typed chain
value directly.
apps/next/hooks/use-link-wallet.test.tsx (1)

28-59: Consider adding a test for the Solana chain path.

The suite only exercises eip155. The buildSiwsMessage path (Solana) has different message formatting logic and is untested. Adding a second it block with chain: 'solana' and a bs58-encoded signature mock would complete coverage here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-link-wallet.test.tsx` around lines 28 - 59, Add a second
test case exercising the Solana path: create a new it block that calls
useLinkWallet with chain: 'solana', address formatted for Solana, and a
signMessage mock that resolves to a bs58-encoded signature; render the hook with
createWrapper(client), call result.current.linkWallet(), then assert signMessage
was called and client.account.link.wallet.verify was invoked with an object
containing body.message (matching buildSiwsMessage/solana format), chain:
'solana', and the bs58 signature, keeping throwOnError: true; reference
useLinkWallet, linkWallet, buildSiwsMessage, and
client.account.link.wallet.verify to locate the code under test.
apps/next/hooks/use-web3-nonce.test.tsx (2)

8-13: Shared mock prevents distinguishing chain branches; consider splitting.

Both eip155.nonce and solana.nonce point to the same vi.fn() reference (line 11). If the implementation accidentally called the wrong branch, the test would still pass. Using separate mocks and asserting only the expected one was called would catch a branch regression.

🛠️ Proposed fix
 function createMockClient() {
-  const nonce = vi.fn().mockResolvedValue({ data: { nonce: 'testnonce' } })
+  const eip155Nonce = vi.fn().mockResolvedValue({ data: { nonce: 'testnonce' } })
+  const solanaNonce = vi.fn().mockResolvedValue({ data: { nonce: 'testnonce' } })
   return {
-    auth: { web3: { eip155: { nonce }, solana: { nonce } } },
+    auth: { web3: { eip155: { nonce: eip155Nonce }, solana: { nonce: solanaNonce } } },
   } as unknown as ReturnType<typeof import('@repo/core').createClient>
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-web3-nonce.test.tsx` around lines 8 - 13, The shared
vi.fn() used in createMockClient makes eip155.nonce and solana.nonce identical;
split them into two distinct mocks (e.g., nonceEip155 and nonceSolana) so the
test can assert which branch was called. Update createMockClient to return
auth.web3.eip155.nonce = nonceEip155 and auth.web3.solana.nonce = nonceSolana
(each mockResolvedValue as needed) and adjust tests to expect the appropriate
mock to have been called and the other not called.

26-36: Add edge-case tests for solana chain, address: undefined, and enabled: false.

The package-level test at packages/react/src/hooks/use-web3-nonce.test.tsx (per context) covers these scenarios. The app-level hook re-exports the same logic, so parity in coverage would be valuable, particularly for the solana code path (which uses a different client method) and the enabled guard (which prevents redundant API calls on address absence).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-web3-nonce.test.tsx` around lines 26 - 36, Add three
edge-case tests mirroring the package-level coverage: (1) for chain: 'solana'
render the hook with address '0x1234' and assert client.auth.web3.solana.nonce
was called with { query: { address: '0x1234' } } and result.current.data?.nonce
equals the mocked value; (2) for address: undefined render useWeb3Nonce({ chain:
'eip155', address: undefined }) and assert the client eip155 nonce method was
not called and result.current.data is undefined; (3) for enabled: false render
useWeb3Nonce({ chain: 'eip155', address: '0x1234', enabled: false }) and assert
no client call was made (client.auth.web3.eip155.nonce not called) and
result.current.data is undefined; use the same helpers (createMockClient,
createWrapper, renderHook, waitFor) and the existing test structure to add these
cases to use-web3-nonce.test.tsx.
apps/next/wallet/types.ts (1)

2-2: Web3Chain is duplicated — re-export from @repo/react instead

packages/react/src/hooks/use-verify-web3-auth.ts already exports Web3Chain = 'eip155' | 'solana', and packages/react/src/index.ts re-exports it. Having a second, identical definition here means a new chain added to the shared package won't automatically propagate to app-local code.

♻️ Proposed fix
-/** SIWE/SIWS chain identifier */
-export type Web3Chain = 'eip155' | 'solana'
+export type { Web3Chain } from '@repo/react'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/wallet/types.ts` at line 2, Remove the duplicate local type
Web3Chain and import the shared type from the react package instead: replace the
local export "export type Web3Chain = 'eip155' | 'solana'" with an import of
Web3Chain from the shared package (the type exported by use-verify-web3-auth.ts
and re-exported in packages/react's index.ts), then update any references in
this file to use the imported Web3Chain to ensure future chain additions
propagate from `@repo/react`.
apps/next/hooks/use-wallet.test.tsx (1)

64-69: Consider adding a test for "chain specified but not in provider"

Currently there's no test covering useWallet('solana') when only the eip155 adapter is registered. This is the key boundary case that verifies the hook returns undefined (not an incorrect adapter) when the requested chain is absent.

♻️ Suggested additional test
+  it('returns undefined when requested chain is not in provider', () => {
+    const { result } = renderHook(() => useWallet('solana'), {
+      wrapper: createWrapper({ eip155: mockEvmAdapter }),
+    })
+    expect(result.current).toBeUndefined()
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-wallet.test.tsx` around lines 64 - 69, Add a unit test in
apps/next/hooks/use-wallet.test.tsx that calls useWallet('solana') while
creating the wrapper with only the eip155 adapter (createWrapper({ eip155:
mockEvmAdapter })) and assert that result.current is undefined; this covers the
boundary where a requested chain (solana) is not registered and ensures
useWallet('solana') does not return the eip155 adapter (reference the useWallet
hook and the existing mockEvmAdapter/mockSolanaAdapter identifiers to locate the
test file and mocks).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/react/src/hooks/use-verify-link-wallet.test.tsx`:
- Around line 33-44: The test fires result.current.mutateAsync inside act but
doesn't await the mutation, causing flakiness; update both test cases to await
the mutation inside the act wrapper so the Promise chain settles before
assertions (i.e., call await result.current.mutateAsync(...) from within the
async act block) so that client.account.link.wallet.verify is guaranteed to have
been invoked before the expect runs.

In `@packages/react/src/hooks/use-verify-web3-auth.test.tsx`:
- Around line 38-91: In the three tests exercising the useVerifyWeb3Auth hook
(the "calls eip155 verify", "calls solana verify" and "POSTs tokens to
authCallbackUrl when set" cases), the calls to result.current.mutateAsync(...)
inside their act(...) callbacks must be awaited; update each act callback to use
await result.current.mutateAsync(...) so the mutation completes before
assertions run (look for the mutateAsync calls in the tests that call
client.auth.web3.eip155.verify, client.auth.web3.solana.verify, and the
fetch-backed authCallbackUrl test).

In `@packages/react/src/hooks/use-verify-web3-auth.ts`:
- Around line 32-50: The verify calls return a wrapper object with a data
property, but the code double-casts to
Web3Eip155VerifyResponse/Web3SolanaVerifyResponse and then reads
verifyResult.token / verifyResult.refreshToken which are undefined; update the
branch that assigns verifyResult (the results of client.auth.web3.eip155.verify
and client.auth.web3.solana.verify) to unwrap the wrapper (e.g., const { data:
verifyResult } = await client.auth.web3.eip155.verify(...) or const
verifyResponse = await ...; const verifyResult = verifyResponse.data) and then
use verifyResult.token and verifyResult.refreshToken when posting to
authCallbackUrl so the actual token values are sent.

---

Outside diff comments:
In `@apps/next/hooks/use-link-wallet.ts`:
- Around line 73-76: The mutationFn currently throws a misleading generic error
when either address or signMessage is missing; update mutationFn in
use-link-wallet.ts to validate each dependency separately (check address and
check signMessage) and throw distinct, descriptive errors (e.g., "No wallet
address" when address is missing and "No signMessage function" or similar when
signMessage is missing) so callers can identify which piece is not wired up.

In `@apps/next/hooks/use-wallet-auth.ts`:
- Around line 79-81: The current guard in the hook checks address, signMessage,
and chain but always throws "No wallet address", which is misleading; update the
check in use-wallet-auth (the block that evaluates address, signMessage, chain)
to detect which of address, signMessage, or chain is missing and throw or return
a clear, specific error message for each (e.g., "No wallet address", "No
signMessage function", "No chain configured") or build a combined message
listing missing fields so callers can immediately see which dependency (address,
signMessage, or chain) is absent.

---

Nitpick comments:
In `@apps/next/hooks/use-link-wallet.test.tsx`:
- Around line 28-59: Add a second test case exercising the Solana path: create a
new it block that calls useLinkWallet with chain: 'solana', address formatted
for Solana, and a signMessage mock that resolves to a bs58-encoded signature;
render the hook with createWrapper(client), call result.current.linkWallet(),
then assert signMessage was called and client.account.link.wallet.verify was
invoked with an object containing body.message (matching buildSiwsMessage/solana
format), chain: 'solana', and the bs58 signature, keeping throwOnError: true;
reference useLinkWallet, linkWallet, buildSiwsMessage, and
client.account.link.wallet.verify to locate the code under test.

In `@apps/next/hooks/use-wallet.test.tsx`:
- Around line 64-69: Add a unit test in apps/next/hooks/use-wallet.test.tsx that
calls useWallet('solana') while creating the wrapper with only the eip155
adapter (createWrapper({ eip155: mockEvmAdapter })) and assert that
result.current is undefined; this covers the boundary where a requested chain
(solana) is not registered and ensures useWallet('solana') does not return the
eip155 adapter (reference the useWallet hook and the existing
mockEvmAdapter/mockSolanaAdapter identifiers to locate the test file and mocks).

In `@apps/next/hooks/use-wallet.ts`:
- Line 15: The conditional uses a redundant ternary when selecting an adapter:
in the use-wallet hook replace the expression ctx.adapters[chain === 'eip155' ?
'eip155' : 'solana'] with a direct lookup using ctx.adapters[chain]; update the
return path that currently reads if (chain) return ctx.adapters[...] to simply
return ctx.adapters[chain] (still guarding for a falsy chain first) so the code
uses the Web3Chain-typed chain value directly.

In `@apps/next/hooks/use-web3-nonce.test.tsx`:
- Around line 8-13: The shared vi.fn() used in createMockClient makes
eip155.nonce and solana.nonce identical; split them into two distinct mocks
(e.g., nonceEip155 and nonceSolana) so the test can assert which branch was
called. Update createMockClient to return auth.web3.eip155.nonce = nonceEip155
and auth.web3.solana.nonce = nonceSolana (each mockResolvedValue as needed) and
adjust tests to expect the appropriate mock to have been called and the other
not called.
- Around line 26-36: Add three edge-case tests mirroring the package-level
coverage: (1) for chain: 'solana' render the hook with address '0x1234' and
assert client.auth.web3.solana.nonce was called with { query: { address:
'0x1234' } } and result.current.data?.nonce equals the mocked value; (2) for
address: undefined render useWeb3Nonce({ chain: 'eip155', address: undefined })
and assert the client eip155 nonce method was not called and result.current.data
is undefined; (3) for enabled: false render useWeb3Nonce({ chain: 'eip155',
address: '0x1234', enabled: false }) and assert no client call was made
(client.auth.web3.eip155.nonce not called) and result.current.data is undefined;
use the same helpers (createMockClient, createWrapper, renderHook, waitFor) and
the existing test structure to add these cases to use-web3-nonce.test.tsx.

In `@apps/next/wallet/types.ts`:
- Line 2: Remove the duplicate local type Web3Chain and import the shared type
from the react package instead: replace the local export "export type Web3Chain
= 'eip155' | 'solana'" with an import of Web3Chain from the shared package (the
type exported by use-verify-web3-auth.ts and re-exported in packages/react's
index.ts), then update any references in this file to use the imported Web3Chain
to ensure future chain additions propagate from `@repo/react`.

In `@packages/react/src/hooks/use-verify-link-wallet.ts`:
- Line 5: The hook use-verify-link-wallet.ts currently imports the Web3Chain
type from a sibling hook use-verify-web3-auth, creating a lateral dependency;
extract Web3Chain into a stable shared types module (e.g.,
packages/react/src/types.ts or packages/react/src/wallet/types.ts), export the
type from there, and update use-verify-link-wallet.ts and use-verify-web3-auth
to import Web3Chain from the new types module to remove the peer-hook coupling.

Comment thread packages/react/src/hooks/use-verify-link-wallet.test.tsx
Comment thread packages/react/src/hooks/use-verify-web3-auth.test.tsx
Comment thread packages/react/src/hooks/use-verify-web3-auth.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
.github/workflows/docu-deploy.yml (1)

44-45: corepack enable should be placed before pnpm install, not after.

--cwd is a valid global Vercel CLI option — unrelated concern here — but the corepack enable placement is the issue: Corepack works by installing shims for package manager binaries so that the version declared in packageManager (in package.json) is enforced at invocation time. Enabling it after pnpm install means the install step already ran without corepack interception.

In practice this isn't broken today because pnpm/action-setup@v4 with version: 10.29.3 already pins pnpm independently, but the step ordering is semantically wrong and will silently fail to enforce the packageManager constraint if the pnpm/action-setup strategy ever changes.

The standard setup order should be: setup-nodepnpm/action-setupcorepack enable → cache → pnpm install.

♻️ Proposed fix: move corepack enable before install
+     - name: Enable Corepack
+       run: corepack enable
      - name: Get pnpm store directory
        shell: bash
        run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_ENV"
      - uses: actions/cache@v4
        with:
          path: ${{ env.STORE_PATH }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
-     - name: Enable Corepack
-       run: corepack enable
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/docu-deploy.yml around lines 44 - 45, The "Enable
Corepack" step is currently placed after the pnpm install step; move the
Corepack enabling step so it runs before any pnpm install invocation.
Specifically, ensure the workflow executes setup-node, then
pnpm/action-setup@v4, then the "Enable Corepack" step (running corepack enable),
followed by caching and the pnpm install step; update the job steps ordering so
the step named "Enable Corepack" appears before the step that runs pnpm install
to ensure Corepack shims intercept the install.
apps/next/vercel.json (1)

3-3: Minor: turbo run build vs turbo build inconsistency across apps.

apps/next uses npx pnpm turbo run build while apps/fastify and apps/docu use the shorthand npx pnpm turbo build. The two forms are equivalent in Turbo, but picking one form consistently across all three files avoids confusion during future edits.

♻️ Align to shorthand form (matching the other two apps)
-  "buildCommand": "cd ../.. && npx pnpm turbo run build --filter=@repo/next",
+  "buildCommand": "cd ../.. && npx pnpm turbo build --filter=@repo/next",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/vercel.json` at line 3, Update the buildCommand entry named
"buildCommand" to use the shorthand Turbo invocation to match the other apps:
replace the string "npx pnpm turbo run build --filter=@repo/next" with the
shorthand form "npx pnpm turbo build --filter=@repo/next" so the apps/next
vercel.json is consistent with apps/fastify and apps/docu.
.github/workflows/next-deploy-e2e.yml (1)

145-149: "Deploy Next" has no build-failure fallback or diagnostic, unlike the Fastify deploy.

The Fastify deploy (lines 110–115) wraps vercel build in an if/else that falls back to a full deploy and emits a ::notice:: annotation. The Next deploy runs vercel build (line 146) without set +e or any error handling: a build failure exits the step immediately, DEPLOY_OUTPUT is never captured, next_url is left empty, and the downstream E2E job silently fails against an empty URL with no diagnostic breadcrumb.

Even if a full-deploy fallback isn't meaningful for Next.js (since --prebuilt requires a successful build artifact), at minimum an explicit ::error:: annotation and early exit would improve debuggability.

♻️ Suggested improvement: explicit failure annotation
-         pnpm exec vercel pull --yes --environment=preview --token=$VERCEL_TOKEN --cwd apps/next
-         pnpm exec vercel build --token=$VERCEL_TOKEN --cwd apps/next
+         pnpm exec vercel pull --yes --environment=preview --token=$VERCEL_TOKEN --cwd apps/next
+
+         if ! pnpm exec vercel build --token=$VERCEL_TOKEN --cwd apps/next; then
+           echo "::error::vercel build failed for apps/next — no prebuilt artifact available for deploy"
+           exit 1
+         fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/next-deploy-e2e.yml around lines 145 - 149, Wrap the Next
build/deploy steps so build failures are detected and annotated: run pnpm exec
vercel build with set +e and capture its output/exit code (similar to how
DEPLOY_OUTPUT captures vercel deploy), then if the build exit code is non‑zero
emit an explicit GitHub Actions annotation (echo "::error::Next build failed:
$BUILD_OUTPUT") and exit early (or optionally run a fallback deploy path), and
ensure DEPLOY_OUTPUT/next_url are only used when the build succeeded; reference
the vercel build invocation, DEPLOY_OUTPUT/BUILD_OUTPUT variables, and next_url
to locate where to add the check and annotation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/fastify/vercel.json`:
- Around line 5-7: The Vercel commands (buildCommand, installCommand,
devCommand) use unversioned "npx pnpm" which can ignore the root packageManager
pin; update each command in apps/fastify vercel.json to explicitly pin pnpm to
the declared version (e.g., use "npx pnpm@10.29.3" for buildCommand,
installCommand, and devCommand) or alternatively enable corepack in .npmrc so
the pinned "pnpm@10.29.3" is respected; ensure you change the three keys
(buildCommand, installCommand, devCommand) to use the chosen pinned invocation
consistently.

---

Nitpick comments:
In @.github/workflows/docu-deploy.yml:
- Around line 44-45: The "Enable Corepack" step is currently placed after the
pnpm install step; move the Corepack enabling step so it runs before any pnpm
install invocation. Specifically, ensure the workflow executes setup-node, then
pnpm/action-setup@v4, then the "Enable Corepack" step (running corepack enable),
followed by caching and the pnpm install step; update the job steps ordering so
the step named "Enable Corepack" appears before the step that runs pnpm install
to ensure Corepack shims intercept the install.

In @.github/workflows/next-deploy-e2e.yml:
- Around line 145-149: Wrap the Next build/deploy steps so build failures are
detected and annotated: run pnpm exec vercel build with set +e and capture its
output/exit code (similar to how DEPLOY_OUTPUT captures vercel deploy), then if
the build exit code is non‑zero emit an explicit GitHub Actions annotation (echo
"::error::Next build failed: $BUILD_OUTPUT") and exit early (or optionally run a
fallback deploy path), and ensure DEPLOY_OUTPUT/next_url are only used when the
build succeeded; reference the vercel build invocation,
DEPLOY_OUTPUT/BUILD_OUTPUT variables, and next_url to locate where to add the
check and annotation.

In `@apps/next/vercel.json`:
- Line 3: Update the buildCommand entry named "buildCommand" to use the
shorthand Turbo invocation to match the other apps: replace the string "npx pnpm
turbo run build --filter=@repo/next" with the shorthand form "npx pnpm turbo
build --filter=@repo/next" so the apps/next vercel.json is consistent with
apps/fastify and apps/docu.

Comment thread apps/fastify/vercel.json Outdated
Comment on lines +5 to +7
"buildCommand": "cd ../.. && npx pnpm turbo build --filter=@repo/fastify",
"installCommand": "cd ../.. && npx pnpm install",
"devCommand": "cd ../.. && npx pnpm dev --filter=@repo/fastify",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check root package.json for packageManager field and examine vercel.json files
cd /repo

echo "=== Root package.json packageManager field ==="
jq '.packageManager' package.json 2>/dev/null || echo "No packageManager field found"

echo -e "\n=== Root package.json name ==="
jq '.name' package.json 2>/dev/null

echo -e "\n=== Checking vercel.json files ==="
for file in apps/fastify/vercel.json apps/docu/vercel.json apps/next/vercel.json; do
  if [ -f "$file" ]; then
    echo -e "\n--- $file ---"
    cat "$file" | head -20
  else
    echo "File not found: $file"
  fi
done

echo -e "\n=== Checking for .npmrc or pnpm-workspace.yaml ==="
ls -la | grep -E '\.npmrc|pnpm-workspace|\.corepackrc'

Repository: blockmatic/basilic

Length of output: 2183


🏁 Script executed:

echo "=== .npmrc content ==="
cat .npmrc

echo -e "\n=== pnpm-workspace.yaml content ==="
cat pnpm-workspace.yaml

Repository: blockmatic/basilic

Length of output: 413


🏁 Script executed:

# Search for other vercel.json or similar deployment configs
echo "=== All vercel.json files in repo ==="
find . -name "vercel.json" -type f 2>/dev/null

echo -e "\n=== Search for 'npx pnpm' pattern in config files ==="
rg "npx pnpm" --type json --type yaml --type toml 2>/dev/null | head -20

Repository: blockmatic/basilic

Length of output: 1048


🏁 Script executed:

echo "=== packages/email/vercel.json content ==="
cat packages/email/vercel.json

Repository: blockmatic/basilic

Length of output: 221


Pin pnpm version in Vercel commands to match the declared packageManager field.

The root package.json declares "packageManager": "pnpm@10.29.3", but all three vercel.json files (apps/fastify, apps/docu, and apps/next) use unversioned npx pnpm. Since .npmrc does not enable ENABLE_EXPERIMENTAL_COREPACK, the unversioned npx pnpm will resolve from the npm registry at runtime and ignore the pinned version, risking silent major-version drift.

Either enable corepack in .npmrc or pin the version explicitly in the commands (e.g., npx pnpm@10 install or npx pnpm@10.29.3 install) to ensure consistent pnpm versions across environments.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/fastify/vercel.json` around lines 5 - 7, The Vercel commands
(buildCommand, installCommand, devCommand) use unversioned "npx pnpm" which can
ignore the root packageManager pin; update each command in apps/fastify
vercel.json to explicitly pin pnpm to the declared version (e.g., use "npx
pnpm@10.29.3" for buildCommand, installCommand, and devCommand) or alternatively
enable corepack in .npmrc so the pinned "pnpm@10.29.3" is respected; ensure you
change the three keys (buildCommand, installCommand, devCommand) to use the
chosen pinned invocation consistently.

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
basilic-docs Error Error Feb 18, 2026 7:12am
basilic-fastify Error Error Feb 18, 2026 7:12am
basilic-next Error Error Feb 18, 2026 7:12am

- await mutateAsync in act for useVerifyLinkWallet/useVerifyWeb3Auth tests
- unwrap data from verify response in use-verify-web3-auth for authCallbackUrl
- distinct error messages in use-link-wallet and use-wallet-auth
- extract Web3Chain to packages/react/src/types, import in apps/next
- use direct chain lookup in use-wallet (ctx.adapters[chain])
- split nonce mocks in use-web3-nonce tests, add edge-case coverage
- add Solana path test for use-link-wallet, undefined-chain test for use-wallet
- eslint-disable SKIP_BUILD in run-e2e-local.mjs
Re-add git.deploymentEnabled for main and develop branches in
apps/next, apps/docu, and apps/fastify vercel.json
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (12)
apps/next/scripts/run-e2e-local.mjs (1)

63-71: SKIP_BUILD=0 / SKIP_BUILD=false will still skip the build.

!process.env.SKIP_BUILD treats any non-empty string as truthy, so SKIP_BUILD=0 or SKIP_BUILD=false unexpectedly skips the build. The header documents SKIP_BUILD=1 as the intended value, but a developer who sets SKIP_BUILD=0 to "disable skipping" will get the opposite effect.

This pattern already exists for SKIP_KILL_PORTS on Line 53, so it's consistent within the file — but worth making explicit in both places if confusion is possible.

🛡️ Optional: guard against `SKIP_BUILD=0` / `SKIP_BUILD=false`
-  // eslint-disable-next-line turbo/no-undeclared-env-vars -- set by root test:e2e or user
-  if (!process.env.SKIP_BUILD) {
+  // eslint-disable-next-line turbo/no-undeclared-env-vars -- set by root test:e2e or user
+  if (process.env.SKIP_BUILD !== '1') {

Apply the same treatment to SKIP_KILL_PORTS on Line 53 for consistency:

-  if (!process.env.SKIP_KILL_PORTS) {
+  if (process.env.SKIP_KILL_PORTS !== '1') {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/scripts/run-e2e-local.mjs` around lines 63 - 71, The current check
uses `!process.env.SKIP_BUILD` which treats any non-empty string (like "0" or
"false") as truthy and incorrectly skips builds; change the condition that
decides whether to run the build to explicitly test the environment variable
value (e.g., only skip when `process.env.SKIP_BUILD === '1'` or another explicit
truthy token), and apply the same explicit-value check to the `SKIP_KILL_PORTS`
check so both `process.env.SKIP_BUILD` and `process.env.SKIP_KILL_PORTS` behave
predictably (use the exact string comparison against the documented token such
as '1' in the `run-e2e-local.mjs` logic that spawns `pnpm ... build:e2e` and the
port-killing branch).
apps/fastify/vercel.json (1)

8-8: Confirm the develop branch deployment target is intentional for this backend.

Switching from deploymentEnabled: false to { "main": true, "develop": true } means every push to develop produces a live Vercel deployment of the Fastify API. Unlike a frontend preview, this backend deployment will carry real CORS settings (Access-Control-Allow-Origin: *) and presumably connect to real downstream services. Verify that:

  1. The develop deployment targets a dedicated staging environment (separate env vars, non-production DB, etc.).
  2. There is no risk of the staging API being reachable as a production-equivalent endpoint.

If develop deployments are not intended to be live, consider using Vercel preview deployment protection or reverting to false for develop while keeping main: true.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/fastify/vercel.json` at line 8, The git deployment setting for Vercel
currently enables both branches via the "git" -> "deploymentEnabled" object with
"main": true and "develop": true; confirm whether enabling "develop" to produce
live backend deployments is intentional and either 1) ensure "develop" is
configured to target a dedicated staging environment (separate env vars,
non-production DB, restricted CORS and endpoints) or 2) revert "develop" to
false and rely on preview/protected deployments while keeping "main": true;
update the "deploymentEnabled" entry accordingly to reflect the chosen option
and add a short repo comment or PR note documenting the decision.
packages/react/src/hooks/use-verify-web3-auth.ts (2)

47-66: Auth callback flow looks correct.

The credentials: 'include' + redirect: 'follow' + explicit window.location.href navigation pattern properly handles cookie-based auth with server-side redirects. One minor note: the fetch to authCallbackUrl has no timeout — if the callback endpoint is unresponsive, the mutation will hang indefinitely. Consider adding an AbortSignal.timeout() if the target environment supports it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/src/hooks/use-verify-web3-auth.ts` around lines 47 - 66, The
fetch to authCallbackUrl in the use-verify-web3-auth hook can hang because it
has no timeout; update the fetch call in the use-verify-web3-auth function to
use an AbortController (or AbortSignal.timeout when available) to enforce a
reasonable timeout, pass signal into fetch, and ensure you abort the controller
on timeout or on cleanup so the mutation doesn't hang waiting for the callback
endpoint.

43-45: Type assertion for response unwrapping works but is fragile.

The as { data: ... } cast correctly unwraps the hey-api response (addressing the prior review), but it will silently break if the response shape changes. A safer approach could be to assert the presence of .data at runtime or use a type guard, though this is acceptable for now given the generated client.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/src/hooks/use-verify-web3-auth.ts` around lines 43 - 45, The
current untyped cast that unwraps the API response into verifyResult (using
verifyResponse as { data: Web3Eip155VerifyResponse | Web3SolanaVerifyResponse
}).data is fragile; change it to first assert at runtime that verifyResponse is
an object with a data property (or use a small type guard function) before
extracting .data, and if the check fails throw/log a clear error; reference the
verifyResult and verifyResponse variables and the Web3Eip155VerifyResponse /
Web3SolanaVerifyResponse types in use-verify-web3-auth.ts so the guard verifies
the shape and then safely assigns verifyResult.
apps/next/hooks/use-wallet-auth.ts (1)

9-14: Duplicated helpers across use-wallet-auth.ts and use-link-wallet.ts.

REJECTION_PATTERNS, isWalletRejection, and buildSiwsMessage are duplicated almost identically in both files. Consider extracting them into a shared module (e.g., @/wallet/utils.ts) to keep things DRY.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-wallet-auth.ts` around lines 9 - 14, The
REJECTION_PATTERNS array, isWalletRejection(error) function, and
buildSiwsMessage(...) are duplicated; extract these helpers into a single shared
module (e.g., wallet utils) and replace the copies in use-wallet-auth.ts and
use-link-wallet.ts with imports from that new module. Create a new file
exporting REJECTION_PATTERNS, isWalletRejection, and buildSiwsMessage, update
both hooks to import those symbols, and ensure any types used by
buildSiwsMessage are exported or adapted so the hooks compile without changing
their local logic.
apps/next/hooks/use-web3-nonce.test.tsx (2)

28-50: No error-path test for a rejected nonce call

Both success-path tests are solid, but there's no coverage for when the nonce endpoint rejects. Since this hook feeds an auth flow, a rejected fetch producing a defined error (and data remaining undefined) is worth asserting.

♻️ Suggested additional test case
+  it('surfaces error when nonce fetch rejects', async () => {
+    const client = createMockClient()
+    const apiError = new Error('network error')
+    vi.mocked(client.auth.web3.eip155.nonce).mockRejectedValueOnce(apiError)
+
+    const { result } = renderHook(() => useWeb3Nonce({ chain: 'eip155', address: '0x1234' }), {
+      wrapper: createWrapper(client),
+    })
+
+    await waitFor(() => expect(result.current.isError).toBe(true))
+    expect(result.current.error).toBe(apiError)
+    expect(result.current.data).toBeUndefined()
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-web3-nonce.test.tsx` around lines 28 - 50, Add a test
covering the error path where the nonce endpoint rejects: in
apps/next/hooks/use-web3-nonce.test.tsx create a new it(...) that uses
createMockClient() but configures client.auth.web3.eip155.nonce (or
solana.nonce) to return a rejected promise (e.g., mockRejectedValueOnce) before
rendering useWeb3Nonce; render the hook with createWrapper(client), await
waitFor that result.current.error is defined and result.current.data is
undefined, and assert the correct client.auth.web3.<chain>.nonce mock was called
while the other chain's nonce was not called (use the same call shape as
existing tests).

58-60: Replace trivial toBeDefined() check with explicit toBe('idle') assertion

In React Query v5, fetchStatus is always initialised to one of 'idle', 'fetching', or 'paused' — never undefined. The waitFor(() => expect(result.current.fetchStatus).toBeDefined()) condition is trivially satisfied on the first render and provides no assurance that the disabled query reached an idle state. Assert the expected settled state explicitly with .toBe('idle') instead.

♻️ Proposed fix
-    await waitFor(() => expect(result.current.fetchStatus).toBeDefined())
+    await waitFor(() => expect(result.current.fetchStatus).toBe('idle'))
     expect(client.auth.web3.eip155.nonce).not.toHaveBeenCalled()
     expect(result.current.data).toBeUndefined()

Apply the same change at line 70.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-web3-nonce.test.tsx` around lines 58 - 60, Replace the
trivial existence assertion with an explicit idle-state check: change the
waitFor assertion that currently checks result.current.fetchStatus with
toBeDefined() to assert toBe('idle') so the test verifies the disabled query
reached the settled idle state; do the same replacement for the second
occurrence around the later assertion (the one mirrored at line 70). Ensure you
reference result.current.fetchStatus in the updated expectations and keep the
surrounding checks for client.auth.web3.eip155.nonce and result.current.data
unchanged.
apps/next/hooks/use-wallet.test.tsx (1)

64-69: Consider adding a test for solana-only fallback when chain is omitted.

The current test covers eip155 ?? solana with both adapters present (eip155 wins). The right-hand side of the ?? — where only solana is registered — isn't exercised.

✨ Suggested additional test
+  it('returns solana adapter when chain omitted and only solana is registered', () => {
+    const { result } = renderHook(() => useWallet(), {
+      wrapper: createWrapper({ solana: mockSolanaAdapter }),
+    })
+    expect(result.current).toEqual(mockSolanaAdapter)
+  })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/next/hooks/use-wallet.test.tsx` around lines 64 - 69, The test coverage
misses the branch where eip155 is absent and the hook should fallback to Solana;
add a new test in use-wallet.test.tsx that calls renderHook(() => useWallet(), {
wrapper: createWrapper({ solana: mockSolanaAdapter }) }) and assert
expect(result.current).toEqual(mockSolanaAdapter) so useWallet's solana-only
fallback is exercised (referencing useWallet, createWrapper, mockSolanaAdapter).
.github/workflows/api-e2e.yml (4)

16-18: cancel-in-progress: false will queue—not cancel—stale PR runs, wasting CI minutes.

For a PR workflow the idiomatic setting is true: when a new commit lands, any still-running run for the same ref is cancelled immediately.

♻️ Proposed fix
 concurrency:
   group: api-e2e-${{ github.ref }}
-  cancel-in-progress: false
+  cancel-in-progress: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/api-e2e.yml around lines 16 - 18, The workflow's
concurrency block currently sets cancel-in-progress: false which queues stale PR
runs; change cancel-in-progress to true in the concurrency section (the
concurrency.group and cancel-in-progress keys) so that when a new run for the
same ref starts it immediately cancels any in-progress run rather than queuing
it.

29-30: Consider adding a timeout-minutes to guard against hung runs.

A frozen Playwright browser or stalled turbo build will hold the runner until GitHub's default 6-hour cap. A shorter limit (e.g. 30–45 min) improves feedback latency and reduces wasted runner time.

♻️ Proposed addition
   build-and-test:
     runs-on: ubuntu-latest
+    timeout-minutes: 45
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/api-e2e.yml around lines 29 - 30, Add a timeout to the
GitHub Actions job "build-and-test" to prevent hung runs: update the job
definition for build-and-test by adding a timeout-minutes property (e.g.,
timeout-minutes: 45) under the job configuration so the runner will cancel the
job if it exceeds the specified duration.

26-26: Simplify the OPEN_ROUTER_API_KEY fallback expression.

Empty string is falsy in GitHub Actions expressions, so the != '' && guard is redundant and adds noise.

♻️ Proposed simplification
-  OPEN_ROUTER_API_KEY: ${{ secrets.OPEN_ROUTER_API_KEY != '' && secrets.OPEN_ROUTER_API_KEY || 'sk-or-v1-dummy-key-for-unit-tests' }}
+  OPEN_ROUTER_API_KEY: ${{ secrets.OPEN_ROUTER_API_KEY || 'sk-or-v1-dummy-key-for-unit-tests' }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/api-e2e.yml at line 26, The fallback expression for
OPEN_ROUTER_API_KEY is overly verbose: remove the redundant "!= '' &&" guard and
simplify the value to use the secret directly with a logical-or fallback (i.e.,
replace the current expression with one that uses secrets.OPEN_ROUTER_API_KEY ||
'sk-or-v1-dummy-key-for-unit-tests') so empty string falsiness is handled by the
OR; update the OPEN_ROUTER_API_KEY entry accordingly.

1-18: Add a permissions block for least-privilege GITHUB_TOKEN access.

Without an explicit permissions declaration the workflow inherits whatever the repository-level default is. For a read-only test pipeline, lock it down explicitly.

🔒️ Proposed fix
 name: API (E2E)
 
+permissions:
+  contents: read
+
 on:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/api-e2e.yml around lines 1 - 18, Add an explicit top-level
GitHub Actions permissions block to the "API (E2E)" workflow to enforce
least-privilege GITHUB_TOKEN access; update the workflow (the file containing
the "name: API (E2E)" and "concurrency: group: api-e2e-${{ github.ref }}"
entries) to include a permissions section granting only the minimum scopes your
E2E tests need (for example: contents: read and packages: read if you only need
repository and package read access), removing implicit broader defaults—place
the permissions block at the top level of the workflow YAML so the workflow runs
with the reduced privileges.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.github/workflows/next-e2e.yml:
- Around line 19-21: The workflow's concurrency block sets cancel-in-progress:
false which mirrors the same risky behavior flagged in api-e2e.yml; update the
concurrency configuration in this file by changing cancel-in-progress to true
(or remove the explicit key to use the default) so in-progress runs are
cancelled when a new run for the same group starts—look for the concurrency
block and the cancel-in-progress key in the next-e2e workflow and make the
change.
- Around line 1-18: The workflow "Next (E2E)" is missing the top-level
permissions block present in api-e2e.yml; add a permissions section at the
top-level of the workflow (alongside name and on) matching api-e2e.yml so the
job has the same required GitHub Actions permissions (e.g., appropriate
read/write scopes for contents, actions, packages, etc.), ensuring the workflow
behaves the same as api-e2e.yml.
- Line 30: The OPEN_ROUTER_API_KEY expression in next-e2e.yml is redundant (same
as api-e2e.yml); simplify by using a single clear fallback pattern for
OPEN_ROUTER_API_KEY (e.g., use the secrets value or a dummy default) and make it
consistent with api-e2e.yml so both workflows use the same expression for
OPEN_ROUTER_API_KEY; update the OPEN_ROUTER_API_KEY line in next-e2e.yml to
match the canonical form used in api-e2e.yml to remove duplication.
- Around line 32-34: The workflow job "build-and-test" is missing a timeout
setting; in the next-e2e.yml job definition (job name build-and-test, currently
with runs-on: ubuntu-latest) add a timeout-minutes field matching the value used
in api-e2e.yml (e.g., timeout-minutes: 10) directly under the job declaration so
the GitHub Actions runner will cancel long-running runs.

In `@apps/fastify/vercel.json`:
- Around line 5-7: The build/install/dev commands use unversioned "npx pnpm"
calls; change each "npx pnpm" in the buildCommand, installCommand, and
devCommand to a version-pinned invocation (e.g. "npx pnpm@<version>") that
matches the packageManager declaration in package.json so the runtime pnpm
version is deterministic; update buildCommand, installCommand, and devCommand to
use the exact version string from packageManager.

---

Nitpick comments:
In @.github/workflows/api-e2e.yml:
- Around line 16-18: The workflow's concurrency block currently sets
cancel-in-progress: false which queues stale PR runs; change cancel-in-progress
to true in the concurrency section (the concurrency.group and cancel-in-progress
keys) so that when a new run for the same ref starts it immediately cancels any
in-progress run rather than queuing it.
- Around line 29-30: Add a timeout to the GitHub Actions job "build-and-test" to
prevent hung runs: update the job definition for build-and-test by adding a
timeout-minutes property (e.g., timeout-minutes: 45) under the job configuration
so the runner will cancel the job if it exceeds the specified duration.
- Line 26: The fallback expression for OPEN_ROUTER_API_KEY is overly verbose:
remove the redundant "!= '' &&" guard and simplify the value to use the secret
directly with a logical-or fallback (i.e., replace the current expression with
one that uses secrets.OPEN_ROUTER_API_KEY ||
'sk-or-v1-dummy-key-for-unit-tests') so empty string falsiness is handled by the
OR; update the OPEN_ROUTER_API_KEY entry accordingly.
- Around line 1-18: Add an explicit top-level GitHub Actions permissions block
to the "API (E2E)" workflow to enforce least-privilege GITHUB_TOKEN access;
update the workflow (the file containing the "name: API (E2E)" and "concurrency:
group: api-e2e-${{ github.ref }}" entries) to include a permissions section
granting only the minimum scopes your E2E tests need (for example: contents:
read and packages: read if you only need repository and package read access),
removing implicit broader defaults—place the permissions block at the top level
of the workflow YAML so the workflow runs with the reduced privileges.

In `@apps/fastify/vercel.json`:
- Line 8: The git deployment setting for Vercel currently enables both branches
via the "git" -> "deploymentEnabled" object with "main": true and "develop":
true; confirm whether enabling "develop" to produce live backend deployments is
intentional and either 1) ensure "develop" is configured to target a dedicated
staging environment (separate env vars, non-production DB, restricted CORS and
endpoints) or 2) revert "develop" to false and rely on preview/protected
deployments while keeping "main": true; update the "deploymentEnabled" entry
accordingly to reflect the chosen option and add a short repo comment or PR note
documenting the decision.

In `@apps/next/hooks/use-wallet-auth.ts`:
- Around line 9-14: The REJECTION_PATTERNS array, isWalletRejection(error)
function, and buildSiwsMessage(...) are duplicated; extract these helpers into a
single shared module (e.g., wallet utils) and replace the copies in
use-wallet-auth.ts and use-link-wallet.ts with imports from that new module.
Create a new file exporting REJECTION_PATTERNS, isWalletRejection, and
buildSiwsMessage, update both hooks to import those symbols, and ensure any
types used by buildSiwsMessage are exported or adapted so the hooks compile
without changing their local logic.

In `@apps/next/hooks/use-wallet.test.tsx`:
- Around line 64-69: The test coverage misses the branch where eip155 is absent
and the hook should fallback to Solana; add a new test in use-wallet.test.tsx
that calls renderHook(() => useWallet(), { wrapper: createWrapper({ solana:
mockSolanaAdapter }) }) and assert
expect(result.current).toEqual(mockSolanaAdapter) so useWallet's solana-only
fallback is exercised (referencing useWallet, createWrapper, mockSolanaAdapter).

In `@apps/next/hooks/use-web3-nonce.test.tsx`:
- Around line 28-50: Add a test covering the error path where the nonce endpoint
rejects: in apps/next/hooks/use-web3-nonce.test.tsx create a new it(...) that
uses createMockClient() but configures client.auth.web3.eip155.nonce (or
solana.nonce) to return a rejected promise (e.g., mockRejectedValueOnce) before
rendering useWeb3Nonce; render the hook with createWrapper(client), await
waitFor that result.current.error is defined and result.current.data is
undefined, and assert the correct client.auth.web3.<chain>.nonce mock was called
while the other chain's nonce was not called (use the same call shape as
existing tests).
- Around line 58-60: Replace the trivial existence assertion with an explicit
idle-state check: change the waitFor assertion that currently checks
result.current.fetchStatus with toBeDefined() to assert toBe('idle') so the test
verifies the disabled query reached the settled idle state; do the same
replacement for the second occurrence around the later assertion (the one
mirrored at line 70). Ensure you reference result.current.fetchStatus in the
updated expectations and keep the surrounding checks for
client.auth.web3.eip155.nonce and result.current.data unchanged.

In `@apps/next/scripts/run-e2e-local.mjs`:
- Around line 63-71: The current check uses `!process.env.SKIP_BUILD` which
treats any non-empty string (like "0" or "false") as truthy and incorrectly
skips builds; change the condition that decides whether to run the build to
explicitly test the environment variable value (e.g., only skip when
`process.env.SKIP_BUILD === '1'` or another explicit truthy token), and apply
the same explicit-value check to the `SKIP_KILL_PORTS` check so both
`process.env.SKIP_BUILD` and `process.env.SKIP_KILL_PORTS` behave predictably
(use the exact string comparison against the documented token such as '1' in the
`run-e2e-local.mjs` logic that spawns `pnpm ... build:e2e` and the port-killing
branch).

In `@packages/react/src/hooks/use-verify-web3-auth.ts`:
- Around line 47-66: The fetch to authCallbackUrl in the use-verify-web3-auth
hook can hang because it has no timeout; update the fetch call in the
use-verify-web3-auth function to use an AbortController (or AbortSignal.timeout
when available) to enforce a reasonable timeout, pass signal into fetch, and
ensure you abort the controller on timeout or on cleanup so the mutation doesn't
hang waiting for the callback endpoint.
- Around line 43-45: The current untyped cast that unwraps the API response into
verifyResult (using verifyResponse as { data: Web3Eip155VerifyResponse |
Web3SolanaVerifyResponse }).data is fragile; change it to first assert at
runtime that verifyResponse is an object with a data property (or use a small
type guard function) before extracting .data, and if the check fails throw/log a
clear error; reference the verifyResult and verifyResponse variables and the
Web3Eip155VerifyResponse / Web3SolanaVerifyResponse types in
use-verify-web3-auth.ts so the guard verifies the shape and then safely assigns
verifyResult.

Reverts npx pnpm to pnpm in build/install/dev commands to fix
'No Next.js version detected' Vercel build error.
@gaboesquivel gaboesquivel merged commit 10acbe7 into main Feb 18, 2026
6 of 9 checks passed
@gaboesquivel gaboesquivel deleted the refactor-wallet-integration branch February 18, 2026 07:19
@coderabbitai coderabbitai Bot mentioned this pull request Feb 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant