Skip to content

feat(extension-wallet): add popup router and navigation#139

Open
David-patrick-chuks wants to merge 6 commits intoancore-org:mainfrom
David-patrick-chuks:feat/79-extension-router-navigation
Open

feat(extension-wallet): add popup router and navigation#139
David-patrick-chuks wants to merge 6 commits intoancore-org:mainfrom
David-patrick-chuks:feat/79-extension-router-navigation

Conversation

@David-patrick-chuks
Copy link
Copy Markdown
Contributor

@David-patrick-chuks David-patrick-chuks commented Mar 24, 2026

Description

Adds client-side routing for the extension popup using React Router v6, including protected/auth-aware navigation flows for welcome, unlock, create account, home, send, receive, history, settings, and session keys.

This PR also adds a reusable popup navigation bar, route-based page titles, a 404 recovery screen, and focused routing tests. A few extension-only config/type issues on main were cleaned up so the extension app can build and test successfully.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🔧 Configuration change
  • ✅ Test addition/improvement

Security Impact

  • This change affects authorization/authentication

This PR introduces route guards for protected extension screens and separates public flows (/welcome, /create-account, /unlock) from authenticated flows. The current auth state is a local demo/session layer for popup routing and is not yet connected to real wallet unlock or key management logic.

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • E2E tests added/updated (if applicable)

Test Coverage

  • Current coverage: __%
  • New/modified code coverage: __%

Manual Testing Steps

  1. Open the extension popup and verify /welcome, /create-account, and /unlock render correctly for unauthenticated users.
  2. Create a demo wallet session and confirm redirects into /home plus navigation to /send, /receive, /history, /settings, and /session-keys.
  3. Verify locked-state redirects send protected routes back to /unlock, and unknown routes show the 404 recovery screen.

Breaking Changes

  • This PR introduces breaking changes

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published

For High-Security Changes

  • I have documented all security assumptions
  • I have considered attack vectors
  • I have added security-focused test cases
  • I have reviewed against the threat model

Related Issues

Closes #79
Related to #

Additional Context

Local validation completed with:

  • pnpm --filter @ancore/extension-wallet test
image
  • pnpm --filter @ancore/extension-wallet build
image

Reviewer Notes

Please focus on:

  • Route structure and redirect behavior
  • Guard behavior for public vs protected extension screens
  • Whether the temporary local auth/session model is acceptable for this issue scope pending backend/wallet integration
  • Popup navigation UX and title updates

Summary by CodeRabbit

Release Notes

  • New Features

    • Added bottom navigation bar for quick access to home, send, receive, transaction history, and settings
    • Implemented authentication system with onboarding flow and account unlock functionality
    • Router-based navigation for multi-screen wallet experience
    • Security settings page for wallet configuration
  • Chores

    • Added react-router-dom dependency
    • Updated build configuration for improved tooling compatibility
    • Enhanced type safety throughout application

@drips-wave
Copy link
Copy Markdown

drips-wave bot commented Mar 24, 2026

@David-patrick-chuks Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

📝 Walkthrough

Walkthrough

The PR implements React Router v6 for the extension wallet with comprehensive authentication guards and navigation, replaces the demo application with a routing-based architecture, adds a navigation bar component, strengthens TypeScript type safety across storage and crypto modules by removing any types, and migrates configuration files to ES modules.

Changes

Cohort / File(s) Summary
Router Implementation
apps/extension-wallet/src/router/index.tsx, apps/extension-wallet/src/router/AuthGuard.tsx, apps/extension-wallet/src/router/__tests__/router.test.tsx
Core routing system with authentication state management, route guards (AuthGuard, PublicOnlyGuard), screen layout wrapper (ProtectedLayout), route-based title synchronization, and comprehensive test coverage for auth flows and navigation scenarios.
Navigation Components
apps/extension-wallet/src/components/Navigation/NavBar.tsx
New sticky bottom navigation bar with 5-column grid of NavLink elements for /home, /send, /receive, /history, /settings routes with conditional active styling via react-router-dom.
App Entrypoints Refactored
apps/extension-wallet/src/App.tsx, apps/extension-wallet/src/main.tsx
Replaced inline demo app implementations with ExtensionRouter integration; removed mock error handling and state management from top-level components, delegating routing control to the new router module.
Type Safety Improvements - Storage
packages/core-sdk/src/storage/types.ts, packages/core-sdk/src/storage/secure-storage-manager.ts, packages/core-sdk/src/storage/__tests__/manager.test.ts
Updated StorageAdapter interface with generic typing (get<T>(), set<T>()), strengthened index signatures from any to unknown, and improved encryption helper type safety (removed unsafe any casts for buffer operations).
Type Safety Improvements - Crypto
packages/crypto/src/encryption.ts, packages/crypto/src/__tests__/encryption-roundtrip.test.ts, packages/crypto/eslint.config.cjs
Switched internal crypto helpers to explicit webcrypto.Crypto type, added Node.js TextEncoder/TextDecoder imports, updated ESLint globals for crypto runtime types.
Type Safety Improvements - UI & Error Handling
apps/extension-wallet/src/errors/ErrorBoundary.tsx, apps/extension-wallet/src/errors/ErrorScreen.tsx, packages/ui-kit/src/components/ui/input.tsx
Updated React component return types from JSX.Element to ReactElement, changed InputProps from interface to type alias, improved error normalization and HOC typing.
Configuration Migrations to ES Modules
apps/extension-wallet/tailwind.config.js, apps/extension-wallet/vite.config.ts, apps/extension-wallet/vitest.config.ts
Converted from CommonJS (module.exports) to ES module exports, updated path resolution to use import.meta.url instead of __dirname, consolidated import statements.
ESLint Configuration Updates
apps/extension-wallet/eslint.config.cjs, packages/account-abstraction/eslint.config.cjs, packages/core-sdk/eslint.config.cjs, packages/ui-kit/eslint.config.cjs
Consolidated TypeScript/React plugin registration, added global declarations (TextEncoder, BufferSource, crypto, Buffer), disabled prop-types and no-undef rules, extended test environment globals (Vitest/Jest).
Type-safe Test Refactoring
apps/extension-wallet/src/errors/__tests__/errors.test.ts, packages/ui-kit/src/__tests__/Form/validation.test.ts, packages/core-sdk/src/storage/__tests__/manager.test.ts
Removed unused test imports, narrowed TypeScript casts from any to specific types, improved mock implementations with generics, replaced @ts-ignore with @ts-expect-error.
Code Formatting & Cleanup
apps/extension-wallet/src/components/PaymentQRCode.tsx, apps/extension-wallet/src/screens/ReceiveScreen.tsx, apps/extension-wallet/src/screens/__tests__/ReceiveScreen.test.tsx, apps/extension-wallet/src/screens/Settings/SecuritySettings.tsx, packages/ui-kit/src/components/Form/*, packages/crypto/src/index.ts
Consolidated multi-line JSX prop declarations into single-line expressions, reformatted interface/type definitions, collapsed import statements, removed unused imports (no functional behavior changes).
Dependency & Export Updates
apps/extension-wallet/package.json, apps/extension-wallet/src/index.ts
Added react-router-dom@^6.20.0 to dependencies; expanded public exports to include NavBar, router exports, and AuthGuard.

Sequence Diagram

sequenceDiagram
    participant Client as Browser/Client
    participant ER as ExtensionRouter
    participant Auth as AuthGuard
    participant Storage as localStorage
    participant Screen as Screen Component
    participant Nav as NavBar

    Client->>ER: Navigate to /
    ER->>Storage: readAuthState()
    Storage-->>ER: AuthState (onboarded, unlocked)
    
    ER->>Auth: Route through AuthGuard
    
    alt First-time user
        Auth->>Storage: Check hasOnboarded
        Auth-->>Client: Redirect to /welcome
    else Onboarded but locked
        Auth->>Storage: Check isUnlocked
        Auth-->>Client: Redirect to /unlock
    else Unlocked user
        Auth->>Storage: Verify auth state
        Auth->>Screen: Render protected route
        Screen-->>Client: Display content + NavBar
        
        Client->>Nav: Click navigation link (e.g., /settings)
        Nav->>ER: Navigate via NavLink
        ER->>Screen: Update screen component
        Screen-->>Client: Render settings page
    end
    
    Client->>Auth: User action (lock/unlock/reset)
    Auth->>Storage: writeAuthState(updated)
    Storage-->>Auth: State persisted
    Auth->>ER: Trigger redirect if needed
    ER-->>Client: Navigate to appropriate route
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related issues

  • Build Extension Router and Navigation #79 (Build Extension Router and Navigation) — This PR directly implements all requirements from the issue including React Router v6 setup, authentication guards, NavBar component, route configuration, page title management, 404 screen, and comprehensive routing tests covering all navigation flows and auth scenarios.

Possibly related PRs

  • feat: implement receive payment screen with QR generation #85 #136 — Both PRs modify apps/extension-wallet/src/components/PaymentQRCode.tsx and apps/extension-wallet/src/screens/ReceiveScreen.tsx, indicating overlapping UI component changes.
  • feat: Add Secure Storage Manager #127 — Both PRs enhance secure storage by updating packages/core-sdk/src/storage/secure-storage-manager.ts and packages/core-sdk/src/storage/types.ts with generic typing and improved encryption helpers.
  • fix formatting  #147 — Both PRs consolidate and refactor apps/extension-wallet/eslint.config.cjs by removing duplication, adjusting React plugin registration, and extending TypeScript rule configuration.

Poem

🐰 Hop, skip, and navigate with cheer!
Routes now guide you far and near,
Auth guards keep the wallets tight,
NavBar shimmers, oh what a sight!
Types are safer, configs refined—
A routing revolution, beautifully designed! 🌟

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.80% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive Most changes directly support the routing implementation, but several type-safety and linting improvements (ESLint configs, storage typing, encryption types, form component types) extend beyond issue #79's scope. Consider separating infrastructure improvements (type safety, linting configs) into a preparatory PR to keep the router feature-focused.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(extension-wallet): add popup router and navigation' accurately and concisely describes the main changes: implementing routing for the extension popup.
Linked Issues check ✅ Passed All core coding requirements from issue #79 have been met: React Router v6 configured, public/protected routes implemented, AuthGuard and navigation bar built, route-based titles added, 404 screen provided, and comprehensive router tests added.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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: 1

🧹 Nitpick comments (4)
apps/extension-wallet/src/router/AuthGuard.tsx (2)

72-101: useMemo dependency on authState negates memoization benefit.

The useMemo hook includes authState in its dependency array (line 100), which means the memoized value is recreated on every state change. Since the action functions (completeOnboarding, unlockWallet, etc.) use setAuthState with functional updates, they don't actually need authState in their closures.

⚡ Proposed optimization
   const value = React.useMemo<AuthContextValue>(
     () => ({
       authState,
       completeOnboarding: (walletName: string) => {
         setAuthState({
           hasOnboarded: true,
           isUnlocked: true,
           walletName: walletName.trim() || DEFAULT_AUTH_STATE.walletName,
           accountAddress: DEFAULT_AUTH_STATE.accountAddress,
         });
       },
       unlockWallet: () => {
         setAuthState((current) => ({
           ...current,
           hasOnboarded: true,
           isUnlocked: true,
         }));
       },
       lockWallet: () => {
         setAuthState((current) => ({
           ...current,
           isUnlocked: false,
         }));
       },
       resetWallet: () => {
         setAuthState(DEFAULT_AUTH_STATE);
       },
     }),
-    [authState]
+    [] // Action functions are stable; authState is read directly in consumers
   );
+
+  // Return a new object each render so consumers get the latest authState
+  return (
+    <AuthContext.Provider value={{ ...value, authState }}>
+      {children}
+    </AuthContext.Provider>
+  );

Alternatively, since authState must be in the context value and will change, consider removing useMemo entirely as the optimization provides no benefit here.

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

In `@apps/extension-wallet/src/router/AuthGuard.tsx` around lines 72 - 101, The
useMemo around value (React.useMemo<AuthContextValue>(... ,[authState])) is
pointless because authState is included in the dependency array so the memoized
object is recreated on every change; either remove useMemo entirely or remove
authState from the dependency array and instead memoize only the action
functions that rely on setAuthState (completeOnboarding, unlockWallet,
lockWallet, resetWallet) and include DEFAULT_AUTH_STATE where needed so the
context value remains stable without depending on authState in the closure.
Ensure you keep references to authState in the context value itself (so
consumers update), but avoid capturing authState inside the memoized
callbacks—use functional setAuthState updates and stable memoization for the
functions or drop useMemo for simplicity.

57-59: Initial mount writes existing state back to storage.

On first render, readAuthState() reads from localStorage, then the effect immediately writes the same value back. This is harmless but unnecessary.

🔧 Optional: skip initial write
+  const isInitialMount = React.useRef(true);
+
   React.useEffect(() => {
+    if (isInitialMount.current) {
+      isInitialMount.current = false;
+      return;
+    }
     writeAuthState(authState);
   }, [authState]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/router/AuthGuard.tsx` around lines 57 - 59, The
effect in AuthGuard.tsx currently calls writeAuthState(authState) on initial
render (after readAuthState()) which is unnecessary; update the React.useEffect
that writes authState so it skips the initial mount (only writes on subsequent
changes). Implement this by introducing an initialization flag (e.g.,
useRef<boolean> or an isInitialized state) checked inside the effect that sets
the flag on first render and prevents calling writeAuthState(authState) until
after that initial load; reference the existing React.useEffect, authState,
readAuthState(), and writeAuthState() when making the change.
apps/extension-wallet/src/router/index.tsx (2)

254-262: Type assertion for location state could be more defensive.

The from state extraction uses a type assertion that could throw if location.state has an unexpected shape in edge cases.

🛡️ Suggested defensive extraction
-  const from = (location.state as { from?: string } | null)?.from ?? '/home';
+  const from =
+    typeof location.state === 'object' &&
+    location.state !== null &&
+    'from' in location.state &&
+    typeof (location.state as Record<string, unknown>).from === 'string'
+      ? (location.state as { from: string }).from
+      : '/home';

Alternatively, consider a small helper function for type-safe state extraction.

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

In `@apps/extension-wallet/src/router/index.tsx` around lines 254 - 262, The
extraction of from using a direct type assertion on location.state is unsafe;
change it to defensively read location?.state and verify the shape before using
it (e.g., check that (location?.state as any)?.from is a string) so you fallback
to '/home' if the value is missing or has the wrong type; update the code around
the from declaration (and any helper you add) to use optional chaining and a
type/typeof check, and ensure handleUnlock/navigation behavior remains the same
(unlockWallet then navigate(from, { replace: true })) so unexpected
location.state shapes no longer throw.

345-355: Uncontrolled form inputs missing accessibility attributes.

The recipient address and amount inputs in SendScreen are uncontrolled (no value/onChange) and lack name, id, and associated <label> elements. While this is a placeholder, consider adding minimal accessibility attributes for consistency with other screens.

♿ Suggested accessibility improvement
         <div className="space-y-3">
+          <label className="block text-sm font-medium text-foreground">
+            Recipient
           <input
+            name="recipient"
             className="w-full rounded-xl border border-border bg-background px-3 py-3 text-sm outline-none transition focus:border-primary"
             placeholder="Recipient address"
           />
+          </label>
+          <label className="block text-sm font-medium text-foreground">
+            Amount
           <input
+            name="amount"
             className="w-full rounded-xl border border-border bg-background px-3 py-3 text-sm outline-none transition focus:border-primary"
             placeholder="Amount"
           />
+          </label>
           <PrimaryButton>Review transaction</PrimaryButton>
         </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/router/index.tsx` around lines 345 - 355, In
SendScreen, the two inputs for recipient address and amount are uncontrolled and
missing accessibility attributes; add minimal accessible markup by giving each
input a unique id and name (e.g., id="recipient" name="recipient", id="amount"
name="amount") and include associated <label> elements for each (or at minimum
aria-label attributes) and wire them to the inputs so screen readers can
announce them; if you intend to manage state, convert the inputs to controlled
components by adding value/onChange handlers in the SendScreen component and
keep the labels/ids in place; ensure PrimaryButton usage remains unchanged.
🤖 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/extension-wallet/src/screens/Settings/SecuritySettings.tsx`:
- Around line 168-177: The ExportWarningView component declares an unused title
prop; remove it from the component signature (the typed props object for
ExportWarningView) and delete any title usage in the JSX props list where
ExportWarningView is rendered (remove the title prop from both call sites that
pass it), leaving only warningText, onConfirm and onCancel; ensure the prop type
and all callers are updated so no unused/undeclared prop remains.

---

Nitpick comments:
In `@apps/extension-wallet/src/router/AuthGuard.tsx`:
- Around line 72-101: The useMemo around value
(React.useMemo<AuthContextValue>(... ,[authState])) is pointless because
authState is included in the dependency array so the memoized object is
recreated on every change; either remove useMemo entirely or remove authState
from the dependency array and instead memoize only the action functions that
rely on setAuthState (completeOnboarding, unlockWallet, lockWallet, resetWallet)
and include DEFAULT_AUTH_STATE where needed so the context value remains stable
without depending on authState in the closure. Ensure you keep references to
authState in the context value itself (so consumers update), but avoid capturing
authState inside the memoized callbacks—use functional setAuthState updates and
stable memoization for the functions or drop useMemo for simplicity.
- Around line 57-59: The effect in AuthGuard.tsx currently calls
writeAuthState(authState) on initial render (after readAuthState()) which is
unnecessary; update the React.useEffect that writes authState so it skips the
initial mount (only writes on subsequent changes). Implement this by introducing
an initialization flag (e.g., useRef<boolean> or an isInitialized state) checked
inside the effect that sets the flag on first render and prevents calling
writeAuthState(authState) until after that initial load; reference the existing
React.useEffect, authState, readAuthState(), and writeAuthState() when making
the change.

In `@apps/extension-wallet/src/router/index.tsx`:
- Around line 254-262: The extraction of from using a direct type assertion on
location.state is unsafe; change it to defensively read location?.state and
verify the shape before using it (e.g., check that (location?.state as
any)?.from is a string) so you fallback to '/home' if the value is missing or
has the wrong type; update the code around the from declaration (and any helper
you add) to use optional chaining and a type/typeof check, and ensure
handleUnlock/navigation behavior remains the same (unlockWallet then
navigate(from, { replace: true })) so unexpected location.state shapes no longer
throw.
- Around line 345-355: In SendScreen, the two inputs for recipient address and
amount are uncontrolled and missing accessibility attributes; add minimal
accessible markup by giving each input a unique id and name (e.g.,
id="recipient" name="recipient", id="amount" name="amount") and include
associated <label> elements for each (or at minimum aria-label attributes) and
wire them to the inputs so screen readers can announce them; if you intend to
manage state, convert the inputs to controlled components by adding
value/onChange handlers in the SendScreen component and keep the labels/ids in
place; ensure PrimaryButton usage remains unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ddc0a3b2-523a-4079-941e-e0ba1f319552

📥 Commits

Reviewing files that changed from the base of the PR and between 95e0066 and 9948e07.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • apps/extension-wallet/package.json
  • apps/extension-wallet/postcss.config.js
  • apps/extension-wallet/src/App.tsx
  • apps/extension-wallet/src/components/Navigation/NavBar.tsx
  • apps/extension-wallet/src/errors/__tests__/errors.test.ts
  • apps/extension-wallet/src/errors/error-handler.ts
  • apps/extension-wallet/src/index.ts
  • apps/extension-wallet/src/main.tsx
  • apps/extension-wallet/src/router/AuthGuard.tsx
  • apps/extension-wallet/src/router/__tests__/router.test.tsx
  • apps/extension-wallet/src/router/index.tsx
  • apps/extension-wallet/src/screens/Settings/SecuritySettings.tsx
  • apps/extension-wallet/src/screens/__tests__/TransactionDetail.test.tsx
  • apps/extension-wallet/tailwind.config.js
  • apps/extension-wallet/tsconfig.json
  • apps/extension-wallet/vite.config.ts
  • apps/extension-wallet/vitest.config.ts

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 (5)
packages/core-sdk/eslint.config.cjs (1)

33-40: Consider adding afterAll and afterEach to test globals.

The test lifecycle hooks afterAll and afterEach are missing from the globals list. If any tests in this package use these hooks, ESLint may flag them as undefined (though no-undef is disabled in the parent override, so this is low risk).

🔧 Suggested addition for completeness
     languageOptions: {
       globals: {
         describe: 'readonly',
         it: 'readonly',
         expect: 'readonly',
         beforeAll: 'readonly',
         beforeEach: 'readonly',
+        afterAll: 'readonly',
+        afterEach: 'readonly',
         jest: 'readonly',
       },
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core-sdk/eslint.config.cjs` around lines 33 - 40, The globals object
in eslint config is missing the test lifecycle hooks afterAll and afterEach;
update the globals mapping (the globals block where describe, it, expect,
beforeAll, beforeEach, jest are defined) to add afterAll: 'readonly' and
afterEach: 'readonly' so ESLint recognizes those Jest hooks as globals.
apps/extension-wallet/src/errors/ErrorBoundary.tsx (1)

206-206: Consider clarifying the ErrorInfo re-export.

This re-exports React's ErrorInfo type (from the import on line 9), while handleError() returns a different ErrorInfo type defined in error-handler.ts. The naming overlap could confuse consumers of this module.

Consider either:

  1. Renaming the export to clarify its origin: export type { ErrorInfo as ReactErrorInfo }
  2. Documenting which ErrorInfo is which in the module's exports

This is pre-existing and not introduced by this PR, so it's optional to address now.

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

In `@apps/extension-wallet/src/errors/ErrorBoundary.tsx` at line 206, The exported
type ErrorInfo conflicts with a different ErrorInfo returned by handleError in
error-handler.ts; update the re-export to disambiguate by renaming it (e.g.,
export type { ErrorInfo as ReactErrorInfo }) or add a clear export
comment/documentation indicating this export is React's ErrorInfo; ensure
references in this file to the original ErrorInfo import (from React) are
updated if the alias is used elsewhere in the module so that consumers and
internal usage point to the correct symbol.
packages/ui-kit/eslint.config.cjs (3)

52-52: Use recursive glob for config ignores if planning to place config files in subdirectories.

Line 52 currently uses *.config.{js,cjs,ts}, which matches only root-level files. No nested config files exist in packages/ui-kit, but if config files may be placed in subdirectories in the future, use **/*.config.{js,cjs,ts} to ensure they are also ignored.

Proposed ignore pattern update
-    ignores: ['dist/**', 'node_modules/**', '*.config.js', '*.config.cjs', '*.config.ts'],
+    ignores: ['dist/**', 'node_modules/**', '**/*.config.js', '**/*.config.cjs', '**/*.config.ts'],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui-kit/eslint.config.cjs` at line 52, The ignores entry currently
uses '*.config.js', '*.config.cjs', '*.config.ts' which only matches root-level
config files; update the ignores array (the ignores: [...] entry) to use a
recursive glob pattern like '**/*.config.{js,cjs,ts}' so config files in
subdirectories are also ignored by ESLint.

21-24: Optional: Scope Node globals to test/config files only.

Line 21–24 enables both browser and node globals for all TS/TSX files. While no source code currently uses Node APIs, tightening this scope would prevent accidental Node global usage in browser code. Node globals could be enabled only for test and config files where they're actually needed.

Proposed config split
   {
     files: ['**/*.{ts,tsx}'],
     languageOptions: {
       parser: tsparser,
       parserOptions: {
         ecmaVersion: 2020,
         sourceType: 'module',
         ecmaFeatures: {
           jsx: true,
         },
       },
       globals: {
-        ...globals.browser,
-        ...globals.node,
+        ...globals.browser,
       },
     },
@@
   },
+  {
+    files: ['**/*.{test,spec}.{ts,tsx}', '**/*.stories.tsx'],
+    languageOptions: {
+      globals: {
+        ...globals.browser,
+        ...globals.node,
+      },
+    },
+  },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/ui-kit/eslint.config.cjs` around lines 21 - 24, The ESLint config
currently spreads both globals.browser and globals.node into the top-level
globals, which enables Node globals project-wide; change this by removing
...globals.node from the top-level globals and instead add an overrides block
that applies globals: { ...globals.node } only to test/config patterns (e.g.,
files matching **/*.{test,spec}.{ts,tsx,js,jsx} and config/**/*), so update the
globals definition and add an override entry referencing the same globals object
to restrict Node globals to tests/configs.

45-49: Replace blanket ESLint rule disable with targeted suppressions for specific stories.

Disabling react-hooks/rules-of-hooks globally for all *.stories.tsx files masks real hook-order and conditional-hook bugs. React's ESLint plugin documentation includes this rule in its recommended set for good reason. Instead, keep the rule enabled and use targeted eslint-disable-next-line react-hooks/rules-of-hooks comments on specific stories where they genuinely conflict with Storybook patterns, documenting why the suppression is needed.

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

In `@packages/ui-kit/eslint.config.cjs` around lines 45 - 49, Remove the blanket
disable of 'react-hooks/rules-of-hooks' for all '*.stories.tsx' in the ESLint
config (the object that currently sets files: ['**/*.stories.tsx'] and rules:
{'react-hooks/rules-of-hooks': 'off'}) and restore the rule to the recommended
config; instead, for any individual story that genuinely conflicts with
Storybook, add a single-line file-local suppression comment
(eslint-disable-next-line react-hooks/rules-of-hooks) immediately above the
offending hook usage in that specific .stories.tsx and include a brief inline
comment explaining why the suppression is necessary.
🤖 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/ui-kit/README.md`:
- Around line 94-101: The Card example imports Card, CardHeader, CardTitle,
CardDescription, CardContent, and CardFooter but uses the Button component
without importing it; update the import statement that currently lists these
symbols to also include Button (i.e., add Button to the destructured import from
'@ancore/ui-kit') so the TSX example compiles when copy-pasted and Button is
available in the example JSX.

---

Nitpick comments:
In `@apps/extension-wallet/src/errors/ErrorBoundary.tsx`:
- Line 206: The exported type ErrorInfo conflicts with a different ErrorInfo
returned by handleError in error-handler.ts; update the re-export to
disambiguate by renaming it (e.g., export type { ErrorInfo as ReactErrorInfo })
or add a clear export comment/documentation indicating this export is React's
ErrorInfo; ensure references in this file to the original ErrorInfo import (from
React) are updated if the alias is used elsewhere in the module so that
consumers and internal usage point to the correct symbol.

In `@packages/core-sdk/eslint.config.cjs`:
- Around line 33-40: The globals object in eslint config is missing the test
lifecycle hooks afterAll and afterEach; update the globals mapping (the globals
block where describe, it, expect, beforeAll, beforeEach, jest are defined) to
add afterAll: 'readonly' and afterEach: 'readonly' so ESLint recognizes those
Jest hooks as globals.

In `@packages/ui-kit/eslint.config.cjs`:
- Line 52: The ignores entry currently uses '*.config.js', '*.config.cjs',
'*.config.ts' which only matches root-level config files; update the ignores
array (the ignores: [...] entry) to use a recursive glob pattern like
'**/*.config.{js,cjs,ts}' so config files in subdirectories are also ignored by
ESLint.
- Around line 21-24: The ESLint config currently spreads both globals.browser
and globals.node into the top-level globals, which enables Node globals
project-wide; change this by removing ...globals.node from the top-level globals
and instead add an overrides block that applies globals: { ...globals.node }
only to test/config patterns (e.g., files matching
**/*.{test,spec}.{ts,tsx,js,jsx} and config/**/*), so update the globals
definition and add an override entry referencing the same globals object to
restrict Node globals to tests/configs.
- Around line 45-49: Remove the blanket disable of 'react-hooks/rules-of-hooks'
for all '*.stories.tsx' in the ESLint config (the object that currently sets
files: ['**/*.stories.tsx'] and rules: {'react-hooks/rules-of-hooks': 'off'})
and restore the rule to the recommended config; instead, for any individual
story that genuinely conflicts with Storybook, add a single-line file-local
suppression comment (eslint-disable-next-line react-hooks/rules-of-hooks)
immediately above the offending hook usage in that specific .stories.tsx and
include a brief inline comment explaining why the suppression is necessary.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 37137faf-c288-4cb8-aef8-0d8e600cf31b

📥 Commits

Reviewing files that changed from the base of the PR and between 9948e07 and ccfd1d8.

📒 Files selected for processing (70)
  • apps/extension-wallet/src/components/SettingsGroup.tsx
  • apps/extension-wallet/src/components/TransactionStatus.tsx
  • apps/extension-wallet/src/errors/ErrorBoundary.tsx
  • apps/extension-wallet/src/errors/ErrorScreen.tsx
  • apps/extension-wallet/src/errors/error-messages.ts
  • apps/extension-wallet/src/errors/index.ts
  • apps/extension-wallet/src/screens/Settings/AboutScreen.tsx
  • apps/extension-wallet/src/screens/Settings/NetworkSettings.tsx
  • apps/extension-wallet/src/screens/Settings/SettingsScreen.tsx
  • apps/extension-wallet/src/screens/Settings/__tests__/settings.test.tsx
  • apps/extension-wallet/src/screens/TransactionDetail.tsx
  • contracts/README.md
  • contracts/account/test_snapshots/test/test_add_session_key.1.json
  • contracts/account/test_snapshots/test/test_add_session_key_emits_event.1.json
  • contracts/account/test_snapshots/test/test_double_initialize.1.json
  • contracts/account/test_snapshots/test/test_execute_emits_event.1.json
  • contracts/account/test_snapshots/test/test_execute_rejects_invalid_nonce.1.json
  • contracts/account/test_snapshots/test/test_execute_validates_nonce_then_increments.1.json
  • contracts/account/test_snapshots/test/test_initialize.1.json
  • contracts/account/test_snapshots/test/test_initialize_emits_event.1.json
  • contracts/account/test_snapshots/test/test_refresh_session_key_ttl.1.json
  • contracts/account/test_snapshots/test/test_revoke_session_key_emits_event.1.json
  • docs/PULL_REQUEST_WORKFLOW.md
  • packages/account-abstraction/eslint.config.cjs
  • packages/account-abstraction/package.json
  • packages/account-abstraction/src/__tests__/account-contract.test.ts
  • packages/account-abstraction/src/account-contract.ts
  • packages/account-abstraction/src/errors.ts
  • packages/account-abstraction/src/index.ts
  • packages/account-abstraction/src/xdr-utils.ts
  • packages/core-sdk/README.md
  • packages/core-sdk/eslint.config.cjs
  • packages/core-sdk/src/__tests__/builder.test.ts
  • packages/core-sdk/src/__tests__/integration.test.ts
  • packages/core-sdk/src/account-transaction-builder.ts
  • packages/core-sdk/src/contract-params.ts
  • packages/core-sdk/src/errors.ts
  • packages/core-sdk/src/storage/__tests__/manager.test.ts
  • packages/core-sdk/src/storage/secure-storage-manager.ts
  • packages/core-sdk/src/storage/types.ts
  • packages/core-sdk/tsconfig.json
  • packages/crypto/src/__tests__/password-strengh.test.ts
  • packages/crypto/src/__tests__/verify-signature.test.ts
  • packages/crypto/src/index.ts
  • packages/crypto/src/password.ts
  • packages/stellar/package.json
  • packages/stellar/src/errors.ts
  • packages/stellar/src/retry.ts
  • packages/types/package.json
  • packages/types/src/__tests__/user-operation.test.ts
  • packages/types/src/index.ts
  • packages/ui-kit/DESIGN_TOKENS.md
  • packages/ui-kit/README.md
  • packages/ui-kit/eslint.config.cjs
  • packages/ui-kit/src/components/address-display.stories.tsx
  • packages/ui-kit/src/components/address-display.test.tsx
  • packages/ui-kit/src/components/address-display.tsx
  • packages/ui-kit/src/components/amount-input.stories.tsx
  • packages/ui-kit/src/components/amount-input.tsx
  • packages/ui-kit/src/components/ui/badge.tsx
  • packages/ui-kit/src/components/ui/button.tsx
  • packages/ui-kit/src/components/ui/card.stories.tsx
  • packages/ui-kit/src/components/ui/card.tsx
  • packages/ui-kit/src/components/ui/input.test.tsx
  • packages/ui-kit/src/components/ui/input.tsx
  • packages/ui-kit/src/components/ui/separator.stories.tsx
  • packages/ui-kit/src/components/ui/separator.tsx
  • packages/ui-kit/tailwind.config.js
  • packages/ui-kit/tsconfig.json
  • packages/ui-kit/tsup.config.ts
💤 Files with no reviewable changes (3)
  • packages/types/src/index.ts
  • packages/crypto/src/tests/password-strengh.test.ts
  • packages/ui-kit/tsup.config.ts
✅ Files skipped from review due to trivial changes (58)
  • apps/extension-wallet/src/screens/Settings/AboutScreen.tsx
  • apps/extension-wallet/src/screens/Settings/tests/settings.test.tsx
  • contracts/account/test_snapshots/test/test_add_session_key.1.json
  • contracts/account/test_snapshots/test/test_add_session_key_emits_event.1.json
  • contracts/account/test_snapshots/test/test_revoke_session_key_emits_event.1.json
  • apps/extension-wallet/src/components/SettingsGroup.tsx
  • apps/extension-wallet/src/screens/Settings/SettingsScreen.tsx
  • contracts/README.md
  • contracts/account/test_snapshots/test/test_double_initialize.1.json
  • contracts/account/test_snapshots/test/test_execute_emits_event.1.json
  • contracts/account/test_snapshots/test/test_execute_validates_nonce_then_increments.1.json
  • contracts/account/test_snapshots/test/test_initialize.1.json
  • contracts/account/test_snapshots/test/test_refresh_session_key_ttl.1.json
  • packages/core-sdk/tsconfig.json
  • packages/stellar/package.json
  • apps/extension-wallet/src/errors/index.ts
  • docs/PULL_REQUEST_WORKFLOW.md
  • packages/account-abstraction/src/errors.ts
  • packages/core-sdk/src/errors.ts
  • packages/crypto/src/index.ts
  • packages/types/package.json
  • apps/extension-wallet/src/screens/Settings/NetworkSettings.tsx
  • contracts/account/test_snapshots/test/test_initialize_emits_event.1.json
  • packages/account-abstraction/src/index.ts
  • packages/core-sdk/README.md
  • packages/types/src/tests/user-operation.test.ts
  • contracts/account/test_snapshots/test/test_execute_rejects_invalid_nonce.1.json
  • packages/account-abstraction/eslint.config.cjs
  • packages/ui-kit/src/components/address-display.test.tsx
  • packages/account-abstraction/package.json
  • packages/account-abstraction/src/tests/account-contract.test.ts
  • packages/ui-kit/src/components/ui/input.test.tsx
  • packages/crypto/src/tests/verify-signature.test.ts
  • packages/ui-kit/src/components/ui/separator.stories.tsx
  • packages/ui-kit/tailwind.config.js
  • packages/ui-kit/src/components/address-display.stories.tsx
  • packages/core-sdk/src/contract-params.ts
  • apps/extension-wallet/src/components/TransactionStatus.tsx
  • packages/stellar/src/retry.ts
  • packages/ui-kit/tsconfig.json
  • packages/stellar/src/errors.ts
  • packages/core-sdk/src/tests/integration.test.ts
  • packages/ui-kit/src/components/ui/card.stories.tsx
  • packages/ui-kit/src/components/ui/input.tsx
  • packages/crypto/src/password.ts
  • apps/extension-wallet/src/errors/ErrorScreen.tsx
  • packages/ui-kit/src/components/ui/separator.tsx
  • packages/ui-kit/src/components/ui/badge.tsx
  • packages/account-abstraction/src/account-contract.ts
  • packages/ui-kit/src/components/ui/button.tsx
  • packages/ui-kit/src/components/ui/card.tsx
  • packages/account-abstraction/src/xdr-utils.ts
  • packages/ui-kit/src/components/amount-input.stories.tsx
  • packages/ui-kit/src/components/amount-input.tsx
  • packages/ui-kit/DESIGN_TOKENS.md
  • packages/ui-kit/src/components/address-display.tsx
  • packages/core-sdk/src/tests/builder.test.ts
  • packages/core-sdk/src/account-transaction-builder.ts

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 (3)
apps/extension-wallet/src/router/index.tsx (1)

346-356: Accessibility: form inputs missing associated labels.

The placeholder inputs in SendScreen lack proper <label> associations, unlike the inputs in CreateAccountScreen and UnlockScreen which correctly wrap inputs with labels. While this is a placeholder screen, adding proper labels now prevents accessibility debt when the real form is implemented.

♿ Suggested fix for accessible form inputs
         <div className="space-y-3">
-          <input
-            className="w-full rounded-xl border border-border bg-background px-3 py-3 text-sm outline-none transition focus:border-primary"
-            placeholder="Recipient address"
-          />
-          <input
-            className="w-full rounded-xl border border-border bg-background px-3 py-3 text-sm outline-none transition focus:border-primary"
-            placeholder="Amount"
-          />
+          <label className="block text-sm font-medium text-foreground">
+            Recipient address
+            <input
+              className="mt-2 w-full rounded-xl border border-border bg-background px-3 py-3 text-sm outline-none transition focus:border-primary"
+              placeholder="Enter recipient address"
+            />
+          </label>
+          <label className="block text-sm font-medium text-foreground">
+            Amount
+            <input
+              className="mt-2 w-full rounded-xl border border-border bg-background px-3 py-3 text-sm outline-none transition focus:border-primary"
+              placeholder="Enter amount"
+            />
+          </label>
           <PrimaryButton>Review transaction</PrimaryButton>
         </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/extension-wallet/src/router/index.tsx` around lines 346 - 356,
SendScreen's two inputs (the "Recipient address" and "Amount" placeholders) lack
associated labels which breaks accessibility; update the SendScreen component to
add proper labels for these fields by either wrapping each input in a <label> or
adding <label htmlFor="..."> plus matching id attributes on the inputs (use
descriptive ids like recipientAddress and amount). Ensure the labels are visible
to screen readers (can be visually hidden if needed) and keep the PrimaryButton
usage unchanged.
apps/extension-wallet/eslint.config.cjs (1)

37-42: Consider keeping @typescript-eslint/no-explicit-any enabled with gradual exceptions.

Disabling no-explicit-any globally for all production code removes a guardrail against type safety regressions. While the PR summary indicates type safety improvements are being made, fully disabling this rule could allow new any usages to slip in unnoticed.

Consider either:

  • Keeping the rule as 'warn' to surface new usages without blocking builds
  • Using targeted // eslint-disable-next-line comments for legitimate cases

The no-undef: off is appropriate for TypeScript projects since TS handles undefined variable checking and ESLint can produce false positives for TS-specific constructs.

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

In `@apps/extension-wallet/eslint.config.cjs` around lines 37 - 42, The config
currently disables '@typescript-eslint/no-explicit-any' globally; change its
setting from 'off' to 'warn' in the ESLint config (the rule name
'@typescript-eslint/no-explicit-any' in the config block) so new any usages are
surfaced but do not fail CI, and for true exceptions use targeted inline
comments (// eslint-disable-next-line `@typescript-eslint/no-explicit-any`) or
file/folder-level overrides rather than a global disable.
packages/crypto/src/encryption.ts (1)

2-3: Use a type-only import for webcrypto to clarify intent.

webcrypto is used only in type positions (return type annotations). While TypeScript's default configuration already elides this import, explicitly marking it as import type makes the intent clear and improves maintainability.

Suggested fix
-import { webcrypto } from 'node:crypto';
+import type { webcrypto } from 'node:crypto';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/crypto/src/encryption.ts` around lines 2 - 3, Change the top-level
import so that webcrypto is imported as a type-only import: replace the current
import of webcrypto from 'node:crypto' with an explicit type import (e.g.,
import type { webcrypto } from 'node:crypto';) while keeping TextDecoder and
TextEncoder as runtime imports from 'node:util'; update any return type
annotations already referencing webcrypto to use the same symbol so the
type-only import is correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/extension-wallet/eslint.config.cjs`:
- Around line 37-42: The config currently disables
'@typescript-eslint/no-explicit-any' globally; change its setting from 'off' to
'warn' in the ESLint config (the rule name '@typescript-eslint/no-explicit-any'
in the config block) so new any usages are surfaced but do not fail CI, and for
true exceptions use targeted inline comments (// eslint-disable-next-line
`@typescript-eslint/no-explicit-any`) or file/folder-level overrides rather than a
global disable.

In `@apps/extension-wallet/src/router/index.tsx`:
- Around line 346-356: SendScreen's two inputs (the "Recipient address" and
"Amount" placeholders) lack associated labels which breaks accessibility; update
the SendScreen component to add proper labels for these fields by either
wrapping each input in a <label> or adding <label htmlFor="..."> plus matching
id attributes on the inputs (use descriptive ids like recipientAddress and
amount). Ensure the labels are visible to screen readers (can be visually hidden
if needed) and keep the PrimaryButton usage unchanged.

In `@packages/crypto/src/encryption.ts`:
- Around line 2-3: Change the top-level import so that webcrypto is imported as
a type-only import: replace the current import of webcrypto from 'node:crypto'
with an explicit type import (e.g., import type { webcrypto } from
'node:crypto';) while keeping TextDecoder and TextEncoder as runtime imports
from 'node:util'; update any return type annotations already referencing
webcrypto to use the same symbol so the type-only import is correct.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e8438b1f-e322-4f57-9ca2-a659b1871e1d

📥 Commits

Reviewing files that changed from the base of the PR and between ccfd1d8 and 7b3d2d9.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (24)
  • apps/extension-wallet/eslint.config.cjs
  • apps/extension-wallet/package.json
  • apps/extension-wallet/src/components/PaymentQRCode.tsx
  • apps/extension-wallet/src/index.ts
  • apps/extension-wallet/src/main.tsx
  • apps/extension-wallet/src/router/index.tsx
  • apps/extension-wallet/src/screens/ReceiveScreen.tsx
  • apps/extension-wallet/src/screens/__tests__/ReceiveScreen.test.tsx
  • apps/extension-wallet/vite.config.ts
  • packages/account-abstraction/eslint.config.cjs
  • packages/core-sdk/eslint.config.cjs
  • packages/crypto/eslint.config.cjs
  • packages/crypto/src/__tests__/encryption-roundtrip.test.ts
  • packages/crypto/src/encryption.ts
  • packages/crypto/src/index.ts
  • packages/ui-kit/eslint.config.cjs
  • packages/ui-kit/src/__tests__/Form/validation.test.ts
  • packages/ui-kit/src/components/Form/AddressInput.tsx
  • packages/ui-kit/src/components/Form/AmountInput.tsx
  • packages/ui-kit/src/components/Form/Form.stories.tsx
  • packages/ui-kit/src/components/Form/Form.tsx
  • packages/ui-kit/src/components/Form/PasswordInput.tsx
  • packages/ui-kit/src/components/Form/validation.ts
  • packages/ui-kit/src/index.ts
✅ Files skipped from review due to trivial changes (21)
  • packages/crypto/eslint.config.cjs
  • packages/ui-kit/src/index.ts
  • apps/extension-wallet/src/components/PaymentQRCode.tsx
  • packages/account-abstraction/eslint.config.cjs
  • apps/extension-wallet/package.json
  • packages/ui-kit/src/components/Form/validation.ts
  • packages/crypto/src/tests/encryption-roundtrip.test.ts
  • apps/extension-wallet/src/screens/ReceiveScreen.tsx
  • packages/ui-kit/src/tests/Form/validation.test.ts
  • packages/core-sdk/eslint.config.cjs
  • packages/ui-kit/eslint.config.cjs
  • apps/extension-wallet/src/index.ts
  • apps/extension-wallet/vite.config.ts
  • packages/ui-kit/src/components/Form/Form.stories.tsx
  • packages/crypto/src/index.ts
  • apps/extension-wallet/src/main.tsx
  • packages/ui-kit/src/components/Form/Form.tsx
  • packages/ui-kit/src/components/Form/AddressInput.tsx
  • packages/ui-kit/src/components/Form/AmountInput.tsx
  • apps/extension-wallet/src/screens/tests/ReceiveScreen.test.tsx
  • packages/ui-kit/src/components/Form/PasswordInput.tsx

@wheval
Copy link
Copy Markdown
Contributor

wheval commented Mar 26, 2026

@David-patrick-chuks please pnpm install and run the prettier command, there are a lot of file changes that were not necessary.

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.

Build Extension Router and Navigation

2 participants