Skip to content

[account-verifier] feat: setup#57

Merged
AdriaCarrera merged 1 commit intomainfrom
account-verifier
Dec 17, 2025
Merged

[account-verifier] feat: setup#57
AdriaCarrera merged 1 commit intomainfrom
account-verifier

Conversation

@GuillemGarciaDev
Copy link
Collaborator

@GuillemGarciaDev GuillemGarciaDev commented Dec 17, 2025

[[account-verifier] feat: setup

Changes 🛠️

app/package

  • New account-verifier app.

Summary by CodeRabbit

  • New Features

    • Launched account-verifier application with multi-step account setup and verification workflow.
    • Added transaction creation, signing, and blockchain broadcasting capabilities.
    • Implemented access key discovery and management dashboard.
    • Enabled network switching between testnet and mainnet environments.
  • Updates

    • Updated FastAuth package dependencies in example applications.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

📝 Walkthrough

Walkthrough

Introduces the account-verifier app, a React + TypeScript + Vite application featuring FastAuth integration, account creation, transaction signing, and network switching. Adds components for a multi-step authentication workflow, hooks for relayer and access key management, a NEAR relayer service, and supporting configuration, styling, and tooling. Also updates imports in an existing example to reflect FastAuth package renames.

Changes

Cohort / File(s) Summary
Project Configuration & Setup
apps/account-verifier/.env.example, apps/account-verifier/.gitignore, apps/account-verifier/package.json, apps/account-verifier/README.md, apps/account-verifier/vite.config.ts
Environment template, git ignore rules, npm package manifest with dependencies/scripts, setup documentation, and Vite build configuration with React and Node polyfills plugins.
TypeScript & Linting Configuration
apps/account-verifier/eslint.config.js, apps/account-verifier/tsconfig.json, apps/account-verifier/tsconfig.app.json, apps/account-verifier/tsconfig.node.json, apps/account-verifier/src/vite-env.d.ts
ESLint config with React hooks and refresh rules, TypeScript configuration with strict mode and ES2020+ targets, and Vite environment type definitions.
HTML & Entry Point
apps/account-verifier/index.html, apps/account-verifier/src/main.tsx
HTML skeleton with root div and script loader; React entry point rendering App wrapped in FastAuthProvider and StrictMode.
Authentication & Configuration
apps/account-verifier/src/auth_config.json, apps/account-verifier/src/config.ts
Auth0 domain, client ID, audience, and contract IDs; Auth0 configuration with redirect callback and provider params.
Core Application Component & Styles
apps/account-verifier/src/App.tsx, apps/account-verifier/src/App.css, apps/account-verifier/src/index.css
App component with React Router setup; global and app-level styling with dark theme, buttons, forms, and responsive utilities.
UI Components
apps/account-verifier/src/components/Accordion.tsx, apps/account-verifier/src/components/Spinner.tsx, apps/account-verifier/src/components/LoginButton.tsx, apps/account-verifier/src/components/LogoutButton.tsx
Reusable accordion, loading spinner, and authentication button components.
Workflow Step Components
apps/account-verifier/src/components/steps/LoginStep.tsx, apps/account-verifier/src/components/steps/CreateAccountStep.tsx, apps/account-verifier/src/components/steps/RequestTransactionStep.tsx, apps/account-verifier/src/components/steps/SignTransactionStep.tsx, apps/account-verifier/src/components/steps/BroadcastStep.tsx, apps/account-verifier/src/components/steps/index.ts
Multi-step workflow UI components for login, account creation, transaction approval, signing, and broadcasting; shared index for re-exports.
Home Page
apps/account-verifier/src/pages/Home.tsx, apps/account-verifier/src/pages/Home.css
Page component integrating authentication, network selection, and access key display; corresponding page-specific styling.
FastAuth Hooks
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx, apps/account-verifier/src/hooks/use-fast-auth-workflow.ts, apps/account-verifier/src/hooks/use-access-keys.ts
Context provider and hook for FastAuth relayer/client initialization with network switching; hook orchestrating multi-step authentication workflow; hook fetching and managing access keys via FastNear API and relayer.
FastAuth Relayer Service
apps/account-verifier/src/services/fast-auth-relayer.ts
NEAR relayer client encapsulating wallet setup, signing, account creation, transfers, and relay sign actions with network-aware contract resolution.
Utilities & Polyfills
apps/account-verifier/src/utils/history.ts, apps/account-verifier/src/polyfills/index.ts, apps/account-verifier/src/polyfills/buffer/index.ts
Browser history instance; Buffer polyfill for non-Node environments.
Example Import Updates
examples/spa/src/hooks/use-fast-auth-workflow.ts
Updated FastAuth package imports: @fast-auth/browser@fast-auth/browser-sdk, @fast-auth/javascript@fast-auth/javascript-provider.

Sequence Diagram

sequenceDiagram
    participant User
    participant App as React App
    participant FastAuth as FastAuth Hook
    participant Relayer as FastAuth Relayer
    participant NEAR as NEAR Network

    User->>App: Initiate Login
    App->>FastAuth: useFastAuth()
    FastAuth->>Relayer: init()
    Relayer->>NEAR: Connect & Load Account
    Relayer-->>FastAuth: Initialized

    User->>App: Click Create Account
    App->>Relayer: createAccount(action)
    Relayer->>NEAR: Sign & Send Transaction
    NEAR-->>Relayer: Account Created

    User->>App: Request Transaction Signature
    App->>Relayer: createTransfer(...)
    Relayer->>NEAR: Fetch Block Hash & Nonce
    NEAR-->>Relayer: Transaction Object

    User->>App: Sign Transaction
    App->>Relayer: relaySignAction(action)
    Relayer->>NEAR: Call sign() on Contract
    NEAR-->>Relayer: Signature

    User->>App: Broadcast Transaction
    App->>Relayer: send(signature, tx)
    Relayer->>NEAR: Submit Signed Tx
    NEAR-->>App: txHash & Confirmation
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • FastAuthRelayer service (apps/account-verifier/src/services/fast-auth-relayer.ts): Substantial NEAR blockchain integration with key management, signing, transaction construction, and error handling across multiple methods—requires careful review for security and correctness.
  • useFastAuthWorkflow hook (apps/account-verifier/src/hooks/use-fast-auth-workflow.ts): Complex state orchestration and async workflow sequencing across login, account creation, transaction approval, and signing steps.
  • useAccessKeys hook (apps/account-verifier/src/hooks/use-access-keys.ts): Multi-step data fetching from FastNear API and relayer, with aggregation logic and per-account error handling.
  • useFastAuthRelayer context (apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx): Provider setup with network persistence, client reinitialization, and cross-component state management.
  • Integration across components, hooks, and services: Multiple files depend on each other; verify correct prop threading, state updates, and error propagation through the workflow steps.

Possibly related PRs

  • Peersyst/near-mobile#207: Implements view_access_key_list fetching via NearAccountClient; this PR's useAccessKeys hook performs the same query pattern through the relayer connection.
  • [TA-4788]: browser sdk #22: Introduces FastAuth browser SDK package renames and new exports; this PR's imports and hook implementations depend on those package additions.

Suggested labels

feature

Suggested reviewers

  • AdriaCarrera

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description includes only a minimal Changes section with one bullet point, missing required details about the setup scope, objectives, and any implementation notes expected by the template. Expand the description to detail what was set up (React + TypeScript + Vite, routing, auth integration, relayer, hooks, components), and explain the purpose or significance of the new app.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title '[account-verifier] feat: setup' directly describes the main change—a new account-verifier app setup—and is clear and specific.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch account-verifier

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

@socket-security
Copy link

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedclsx@​2.0.01001009480100
Addedcross-env@​7.0.310010010082100
Addedclass-transformer@​0.5.110010010082100
Addedclass-validator@​0.14.010010010087100

View full report

Copy link

@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: 12

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

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

⚠️ Outside diff range comments (2)
examples/spa/src/hooks/use-fast-auth-workflow.ts (2)

115-115: Unsafe non-null assertion on parseNearAmount.

The non-null assertion operator (!) is used on parseNearAmount("0.01"), but parseNearAmount can return null if parsing fails. This could cause a runtime error.

Apply this diff to add proper null handling:

-const action = await signer?.createSignAction(signatureRequest, { deposit: BigInt(parseNearAmount("0.01")!) });
+const amount = parseNearAmount("0.01");
+if (!amount) {
+    throw new Error("Failed to parse NEAR amount");
+}
+const action = await signer?.createSignAction(signatureRequest, { deposit: BigInt(amount) });

135-137: Remove @ts-ignore and fix type incompatibility.

The @ts-ignore comment suppresses TypeScript errors, which indicates a type incompatibility with FastAuthSignature.fromBase64(). Instead of suppressing the error, the underlying type issue should be resolved.

Please investigate why TypeScript is flagging this line and either:

  1. Fix the type incompatibility (e.g., by properly typing result.status.SuccessValue)
  2. Use a proper type assertion if the types are known to be correct
  3. Add a more specific @ts-expect-error with a comment explaining why it's necessary
🟡 Minor comments (9)
apps/account-verifier/src/utils/history.ts-1-2 (1)

1-2: Remove unused history instance.

This file is not imported or used anywhere in the codebase. The app correctly uses <BrowserRouter> from react-router-dom (in App.tsx), which is the proper approach for React Router v7. Delete apps/account-verifier/src/utils/history.ts as dead code.

apps/account-verifier/index.html-7-7 (1)

7-7: Customize the page title.

The title still uses the default Vite template value. Update it to reflect the account-verifier app's purpose.

Apply this diff:

-    <title>Vite + React + TS</title>
+    <title>Account Verifier</title>
apps/account-verifier/src/components/steps/RequestTransactionStep.tsx-89-89 (1)

89-89: Misleading status message.

The message "Requesting transaction approval..." displays when transferRequested is true, but at that point the request has already been initiated (not currently in progress). Consider rewording to "Transaction approval requested" or removing it if not needed.

-            {transferRequested && <p>Requesting transaction approval...</p>}
+            {transferRequested && <p>Transaction approval requested ✓</p>}
apps/account-verifier/src/pages/Home.tsx-250-256 (1)

250-256: Duplicate error display for accessKeysError.

accessKeysError is rendered at lines 150-154 within the Access Keys section and again here at line 254. This could confuse users by showing the same error twice.

Consider removing the accessKeysError from this bottom section since it's already displayed contextually within the Access Keys section.

-            {(fastAuthError || accessKeysError) && (
+            {fastAuthError && (
                 <section style={{ borderColor: "#f87171" }}>
                     <h2 style={{ color: "#f87171" }}>Error</h2>
                     {fastAuthError && <p>FastAuth Error: {fastAuthError.message}</p>}
-                    {accessKeysError && <p>Access Keys Error: {accessKeysError.message}</p>}
                 </section>
             )}
apps/account-verifier/src/hooks/use-fast-auth-workflow.ts-103-115 (1)

103-115: Guard against null publicKey before using non-null assertion.

Line 104 uses publicKey! which will throw if publicKey is null. Add an explicit check to provide a meaningful error.

 const requestTransactionSignature = async (accountId: string, receiverId: string, amount: string) => {
+    if (!publicKey) {
+        throw new Error("Public key not available");
+    }
-    const tx = await relayer?.createTransfer(accountId, PublicKey.fromString(publicKey!), receiverId, amount);
+    const tx = await relayer?.createTransfer(accountId, PublicKey.fromString(publicKey), receiverId, amount);
     if (!tx) {
         throw new Error("Transaction not created");
     }
apps/account-verifier/src/hooks/use-fast-auth-workflow.ts-141-147 (1)

141-147: Remove the @ts-ignore and properly type the signature payload.

The @ts-ignore bypasses a valid type error. Instead, add a type guard to verify result.status and SuccessValue exist before accessing them, similar to the pattern in packages/sdks/react/src/core/signers/signer.ts:

if (typeof result.status !== "object" || !("SuccessValue" in result.status)) {
    throw new Error("Failed to sign delegate action");
}
const signature = FastAuthSignature.fromBase64(result.status.SuccessValue!);

Alternatively, use a type assertion: FastAuthSignature.fromBase64(result.status.SuccessValue as string).

apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx-135-141 (1)

135-141: Error message references incorrect provider name.

The error message says "useFastAuthRelayer must be used within a FastAuthRelayerProvider" but the actual provider is named FastAuthProvider and the hook is useFastAuth.

 export function useFastAuth(): FastAuthContextType {
     const context = useContext(FastAuthContext);
     if (context === null) {
-        throw new Error("useFastAuthRelayer must be used within a FastAuthRelayerProvider");
+        throw new Error("useFastAuth must be used within a FastAuthProvider");
     }
     return context;
 }
apps/account-verifier/src/services/fast-auth-relayer.ts-145-164 (1)

145-164: Null assertion on parseNearAmount result.

parseNearAmount(amount)! uses a non-null assertion, but parseNearAmount can return null for invalid inputs. This could cause a runtime error.

+        const parsedAmount = parseNearAmount(amount);
+        if (!parsedAmount) {
+            throw new Error(`Invalid NEAR amount: ${amount}`);
+        }
+
         const tx = createTransaction(
             signerId,
             signerPublicKey,
             receiverId,
             nonce,
-            [transfer(BigInt(parseNearAmount(amount)!))],
+            [transfer(BigInt(parsedAmount))],
             base_decode(accessKey.block_hash),
         );
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx-114-118 (1)

114-118: Mutating relayer state may cause stale reference issues.

After relayer.switchNetwork(newNetwork), calling setRelayer(relayer) with the same object reference won't trigger React re-renders in consumers that depend on referential equality. Consider creating a new relayer instance or using a different state update pattern.

             if (relayer) {
                 await relayer.switchNetwork(newNetwork);
-                setRelayer(relayer);
+                // Force state update with a new reference pattern or reinitialize
+                await initializeRelayer(newNetwork);
-                setIsRelayerInitialized(true);
-                await initializeClient(relayer.getConnection().connection, newNetwork);

Alternatively, if performance is a concern, ensure consumers use the relayer's methods rather than relying on referential equality.

Committable suggestion skipped: line range outside the PR's diff.

🧹 Nitpick comments (15)
apps/account-verifier/.gitignore (1)

1-24: Comprehensive .gitignore for Vite + React project.

The file covers all essential patterns: logs, build outputs, dependencies, and editor artifacts. The preservation of .vscode/extensions.json (line 17) is a good practice for team configuration.

Optional enhancement for future consideration: If the project uses environment variables in .env files (without .local suffix) as checked-in templates, the current setup is fine. However, if bare .env files should be ignored, consider adding a pattern for /.env (with leading slash to match the root only).

apps/account-verifier/src/components/steps/BroadcastStep.tsx (1)

6-6: Use specific typing instead of any.

The result prop uses any, which defeats TypeScript's type safety. Consider defining a specific type or interface for the result data.

+interface TransactionResult {
+    // Define the expected shape of result
+    transaction: unknown;
+    // Add other relevant fields
+}
+
 interface BroadcastStepProps {
-    result: any;
+    result: TransactionResult | null;
     txHash: string | null;
apps/account-verifier/src/components/steps/CreateAccountStep.tsx (1)

58-58: Use consistent naming convention for input name.

The input name "accountid" (all lowercase) is inconsistent with typical JavaScript/HTML naming conventions.

Apply this diff for better consistency:

-                        name="accountid" 
+                        name="accountId" 

And update line 28 accordingly:

-        const accountId = formData.get("accountid") as string;
+        const accountId = formData.get("accountId") as string;
apps/account-verifier/src/components/Accordion.tsx (1)

10-33: Add ARIA attributes for better accessibility.

The accordion lacks proper ARIA attributes, making it harder for screen readers to convey the expand/collapse state.

Apply this diff to improve accessibility:

 const Accordion: React.FC<AccordionProps> = ({ title, expanded, onClick, children }) => {
+    const contentId = React.useId();
+
     return (
         <div style={{ border: "1px solid #333", borderRadius: 8, marginBottom: 16, background: "#23272f" }}>
             <button
                 type="button"
                 onClick={onClick}
+                aria-expanded={expanded}
+                aria-controls={contentId}
                 style={{
                     width: "100%",
                     textAlign: "left",
                     padding: "1rem",
                     background: "#181a20",
                     border: "none",
                     borderRadius: "8px 8px 0 0",
                     fontWeight: 600,
                     cursor: "pointer",
                     outline: "none",
                     color: "#f1f1f1",
                 }}
             >
                 {title}
             </button>
-            {expanded && <div style={{ padding: "1rem", color: "#e0e0e0" }}>{children}</div>}
+            {expanded && (
+                <div id={contentId} role="region" style={{ padding: "1rem", color: "#e0e0e0" }}>
+                    {children}
+                </div>
+            )}
         </div>
     );
 };
apps/account-verifier/src/config.ts (2)

24-32: Cache getConfig() result to avoid repeated object creation.

The current implementation calls getConfig() four times, creating four separate objects. This is inefficient and can be optimized by caching the result.

Apply this diff:

+const config = getConfig();
+
 export const providerConfig = {
-    domain: getConfig().domain,
-    clientId: getConfig().clientId,
+    domain: config.domain,
+    clientId: config.clientId,
     onRedirectCallback,
     authorizationParams: {
         redirect_uri: window.location.origin,
-        ...(getConfig().audience ? { audience: getConfig().audience } : null),
+        ...(config.audience ? { audience: config.audience } : {}),
         scope: "transaction:send-transaction transaction:read-transaction test:send-test",
     },
 };

20-20: Use empty object instead of null in spread operator.

Spreading null works but is unconventional. Using an empty object is more idiomatic and clearer.

Apply this diff:

     return {
         domain: configJson.domain,
         clientId: configJson.clientId,
-        ...(audience ? { audience } : null),
+        ...(audience ? { audience } : {}),
     };
apps/account-verifier/src/components/steps/LoginStep.tsx (1)

39-45: Clarify the button's intent or rename the callback.

When logged in, the "Create Account" button triggers onLogin, which is semantically confusing. If this is intentional (e.g., onLogin advances the workflow step), consider renaming onLogin to something like onProceed or onNextStep in LoginStepProps to better reflect its purpose.

apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (2)

14-14: Consider typing result properly instead of any.

Using any loses type safety. Based on usage at line 145, this appears to be a transaction result with status.SuccessValue. Define a proper type for the relayer response.


83-83: Unnecessary dependencies in useCallback.

relayer and network are included in the dependency array but are not used within fetchPublicKey. This can cause unnecessary re-computation. Consider removing them, or if the intent is to refetch when network changes, add an explicit reset of workflow state when network changes.

-    }, [isClientInitialized, client, relayer, network]);
+    }, [isClientInitialized, client]);
apps/account-verifier/src/hooks/use-access-keys.ts (3)

22-34: Add timeout and abort signal to external API fetch.

The fetch call to FastNear API lacks a timeout mechanism. If the API is slow or unresponsive, this could leave the hook in a loading state indefinitely.

-async function getAccountIdsByPublicKey(publicKey: string, network: "testnet" | "mainnet"): Promise<string[]> {
+async function getAccountIdsByPublicKey(publicKey: string, network: "testnet" | "mainnet", signal?: AbortSignal): Promise<string[]> {
     const apiBase = network === "mainnet" ? MAINNET_FASTNEAR_API_BASE : TESTNET_FASTNEAR_API_BASE;
     try {
-        const response = await fetch(`${apiBase}/public_key/${encodeURIComponent(publicKey)}/all`);
+        const response = await fetch(`${apiBase}/public_key/${encodeURIComponent(publicKey)}/all`, { signal });
         if (!response.ok) {
             throw new Error(`Failed to fetch account IDs: ${response.statusText}`);
         }

82-102: Sequential account fetching may be slow for many accounts.

The loop fetches access keys sequentially. For accounts with many linked IDs, consider using Promise.allSettled for parallel fetching to improve performance.

-                for (const accountId of accountIdsList) {
-                    try {
-                        const result = await connection.connection.provider.query({
-                            request_type: "view_access_key_list",
-                            finality: "final",
-                            account_id: accountId,
-                        });
-
-                        // The result contains an array of access keys with public_key and access_key
-                        const keys: AccessKeyInfo[] = (result as any).keys.map((item: any) => ({
-                            publicKey: item.public_key,
-                            accessKey: item.access_key,
-                            accountId: accountId,
-                        }));
-
-                        allAccessKeys.push(...keys);
-                    } catch (err) {
-                        console.error(`Failed to fetch access keys for account ${accountId}:`, err);
-                        // Continue with other accounts even if one fails
-                    }
-                }
+                const results = await Promise.allSettled(
+                    accountIdsList.map(async (accountId) => {
+                        const result = await connection.connection.provider.query({
+                            request_type: "view_access_key_list",
+                            finality: "final",
+                            account_id: accountId,
+                        });
+                        return (result as any).keys.map((item: any) => ({
+                            publicKey: item.public_key,
+                            accessKey: item.access_key,
+                            accountId,
+                        }));
+                    }),
+                );
+
+                for (const result of results) {
+                    if (result.status === "fulfilled") {
+                        allAccessKeys.push(...result.value);
+                    } else {
+                        console.error("Failed to fetch access keys for an account:", result.reason);
+                    }
+                }

91-95: Avoid using any type for API response mapping.

The (result as any).keys cast loses type safety. Consider defining a typed response interface for the query result.

+interface AccessKeyListResult {
+    keys: Array<{
+        public_key: string;
+        access_key: AccessKeyView;
+    }>;
+}

-                        const keys: AccessKeyInfo[] = (result as any).keys.map((item: any) => ({
+                        const keys: AccessKeyInfo[] = (result as AccessKeyListResult).keys.map((item) => ({
                             publicKey: item.public_key,
                             accessKey: item.access_key,
                             accountId: accountId,
                         }));
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)

95-100: Disabled exhaustive-deps rule may hide bugs.

The useEffect depends on network but calls initializeRelayer(network). If initializeRelayer changes (unlikely but possible), this could cause stale closures. Consider including initializeRelayer in the dependency array or extracting stable initialization logic.

apps/account-verifier/src/services/fast-auth-relayer.ts (2)

31-38: Class name conflicts with existing FastAuthRelayer in the SDK package.

There's already a FastAuthRelayer class in packages/sdks/react/src/core/relayer/relayer.ts with different functionality. This naming collision could cause confusion. Consider renaming to something more specific like NearRelayerService or AccountVerifierRelayer.


36-38: Use proper types instead of any for NEAR connection and account.

Using any for config, near, and account loses type safety. Import and use proper types from near-api-js.

+import { Near, NearConfig } from "near-api-js";

 class FastAuthRelayer {
     private keyStore: keyStores.InMemoryKeyStore;
     private keyPair: KeyPair;
     private accountId: string;
     private networkId: NetworkId;
-    private config: any;
-    private near: any;
-    private account: any;
+    private config: NearConfig;
+    private near: Near | null;
+    private account: Account | null;
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8f0dc1 and 9e3ca1a.

⛔ Files ignored due to path filters (3)
  • apps/account-verifier/public/vite.svg is excluded by !**/*.svg
  • apps/account-verifier/src/assets/react.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (37)
  • apps/account-verifier/.env.example (1 hunks)
  • apps/account-verifier/.gitignore (1 hunks)
  • apps/account-verifier/README.md (1 hunks)
  • apps/account-verifier/eslint.config.js (1 hunks)
  • apps/account-verifier/index.html (1 hunks)
  • apps/account-verifier/package.json (1 hunks)
  • apps/account-verifier/src/App.css (1 hunks)
  • apps/account-verifier/src/App.tsx (1 hunks)
  • apps/account-verifier/src/auth_config.json (1 hunks)
  • apps/account-verifier/src/components/Accordion.tsx (1 hunks)
  • apps/account-verifier/src/components/LoginButton.tsx (1 hunks)
  • apps/account-verifier/src/components/LogoutButton.tsx (1 hunks)
  • apps/account-verifier/src/components/Spinner.tsx (1 hunks)
  • apps/account-verifier/src/components/steps/BroadcastStep.tsx (1 hunks)
  • apps/account-verifier/src/components/steps/CreateAccountStep.tsx (1 hunks)
  • apps/account-verifier/src/components/steps/LoginStep.tsx (1 hunks)
  • apps/account-verifier/src/components/steps/RequestTransactionStep.tsx (1 hunks)
  • apps/account-verifier/src/components/steps/SignTransactionStep.tsx (1 hunks)
  • apps/account-verifier/src/components/steps/index.ts (1 hunks)
  • apps/account-verifier/src/config.ts (1 hunks)
  • apps/account-verifier/src/hooks/use-access-keys.ts (1 hunks)
  • apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1 hunks)
  • apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (1 hunks)
  • apps/account-verifier/src/index.css (1 hunks)
  • apps/account-verifier/src/main.tsx (1 hunks)
  • apps/account-verifier/src/pages/Home.css (1 hunks)
  • apps/account-verifier/src/pages/Home.tsx (1 hunks)
  • apps/account-verifier/src/polyfills/buffer/index.ts (1 hunks)
  • apps/account-verifier/src/polyfills/index.ts (1 hunks)
  • apps/account-verifier/src/services/fast-auth-relayer.ts (1 hunks)
  • apps/account-verifier/src/utils/history.ts (1 hunks)
  • apps/account-verifier/src/vite-env.d.ts (1 hunks)
  • apps/account-verifier/tsconfig.app.json (1 hunks)
  • apps/account-verifier/tsconfig.json (1 hunks)
  • apps/account-verifier/tsconfig.node.json (1 hunks)
  • apps/account-verifier/vite.config.ts (1 hunks)
  • examples/spa/src/hooks/use-fast-auth-workflow.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (12)
📚 Learning: 2025-04-07T12:08:24.795Z
Learnt from: obnol
Repo: Peersyst/near-mobile PR: 154
File: packages/frontend/auth/package.json:0-0
Timestamp: 2025-04-07T12:08:24.795Z
Learning: The BiometricsService is correctly re-exported in /packages/frontend/auth/src/data-access/services/index.ts with the line `export * from "./biometrics.service";`, validating the export path in package.json.

Applied to files:

  • apps/account-verifier/src/components/steps/index.ts
  • apps/account-verifier/src/main.tsx
  • apps/account-verifier/package.json
  • apps/account-verifier/src/polyfills/index.ts
  • examples/spa/src/hooks/use-fast-auth-workflow.ts
  • apps/account-verifier/src/services/fast-auth-relayer.ts
📚 Learning: 2025-09-10T13:23:58.048Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 571
File: packages/shared/api/src/index.ts:33-33
Timestamp: 2025-09-10T13:23:58.048Z
Learning: The packages/shared/api package exports source files directly (./src/index.ts) rather than compiled output because it's auto-generated by openapi-typescript-codegen and this export strategy is intentional for this shared package.

Applied to files:

  • apps/account-verifier/src/components/steps/index.ts
  • apps/account-verifier/tsconfig.json
  • apps/account-verifier/package.json
📚 Learning: 2025-06-06T15:08:15.340Z
Learnt from: JordiParraCrespo
Repo: Peersyst/near-mobile PR: 331
File: packages/shared/utils/src/index.ts:1-1
Timestamp: 2025-06-06T15:08:15.340Z
Learning: The packages/shared/utils package has a properly structured error module with an index.ts file that exports from ./decorator. The export * from "./error" statement in the main index works correctly and allows importing createErrorHandlerDecorator from shared/utils.

Applied to files:

  • apps/account-verifier/src/components/steps/index.ts
📚 Learning: 2025-08-14T14:53:11.507Z
Learnt from: AdriaCarrera
Repo: Peersyst/near-mobile PR: 520
File: turbo.json:0-0
Timestamp: 2025-08-14T14:53:11.507Z
Learning: In turbo.json, package.json files can be legitimate outputs when build tasks modify them during execution (e.g., version updates, metadata injection). In such cases, including package.json in the outputs array ensures proper cache restoration of the modified files.

Applied to files:

  • apps/account-verifier/tsconfig.json
📚 Learning: 2025-08-29T16:22:11.387Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 553
File: apps/mobile/src/modules/token/screens/npro-pre-staking-token-details/screens/npro-pre-staking-token-details-general/containers/npro-pre-staking-token-details-actions/npro-pre-staking-token-details-item/npro-pre-staking-token-details-item.tsx:3-3
Timestamp: 2025-08-29T16:22:11.387Z
Learning: In the NEAR mobile app codebase, the team prefers to use the React namespace (e.g., React.ReactNode) instead of standalone imports (e.g., ReactNode) from the react package.

Applied to files:

  • apps/account-verifier/src/main.tsx
  • apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx
  • examples/spa/src/hooks/use-fast-auth-workflow.ts
📚 Learning: 2025-04-30T08:57:52.130Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 228
File: packages/frontend/price/src/ui/queries/use-convert-amount-to-fiat.ts:1-8
Timestamp: 2025-04-30T08:57:52.130Z
Learning: In this codebase, BigNumber is set up as a global variable (likely through polyfills) and should be used without explicit imports.

Applied to files:

  • apps/account-verifier/src/polyfills/buffer/index.ts
📚 Learning: 2025-04-30T08:57:52.130Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 228
File: packages/frontend/price/src/ui/queries/use-convert-amount-to-fiat.ts:1-8
Timestamp: 2025-04-30T08:57:52.130Z
Learning: In this codebase, developers expect BigNumber to be available globally without explicit imports, though the pattern is inconsistent across files.

Applied to files:

  • apps/account-verifier/src/polyfills/buffer/index.ts
📚 Learning: 2025-09-18T13:10:13.778Z
Learnt from: JordiParraCrespo
Repo: Peersyst/bitcoin-light PR: 85
File: packages/shared/blockchain/src/wci/chains/nervos/providers/dao/nervos-dao.provider.ts:1-1
Timestamp: 2025-09-18T13:10:13.778Z
Learning: In the nervos-dao.provider.ts file in the Bitcoin Light codebase, BigNumber is used on line 117 but needs to be explicitly imported, even though it may be available globally elsewhere in the codebase.

Applied to files:

  • apps/account-verifier/src/polyfills/buffer/index.ts
  • apps/account-verifier/src/polyfills/index.ts
📚 Learning: 2025-06-09T09:14:11.981Z
Learnt from: JordiParraCrespo
Repo: Peersyst/near-mobile PR: 342
File: apps/mobile/src/modules/wallet/hooks/use-get-wallet-account-total-balance/use-get-wallet-account-total-balance.ts:26-28
Timestamp: 2025-06-09T09:14:11.981Z
Learning: In the near-mobile project, when calculating derived values from query results in React hooks, use useMemo with proper dependencies (like queryResult.data and fiatPrice.data) to avoid unnecessary re-renders and reference changes. This pattern is established in files like use-get-wallet-amounts-in-chain.ts and should be followed consistently across wallet-related hooks.

Applied to files:

  • apps/account-verifier/src/hooks/use-access-keys.ts
  • examples/spa/src/hooks/use-fast-auth-workflow.ts
📚 Learning: 2025-05-30T13:25:36.454Z
Learnt from: JordiParraCrespo
Repo: Peersyst/near-mobile PR: 305
File: apps/mobile/src/modules/wallet-selector/containers/sign-request/sign-request-form/sign-request-form.tsx:32-32
Timestamp: 2025-05-30T13:25:36.454Z
Learning: In wallet selector sign request forms, useRef is intentionally used to capture the initial account ID for comparison with the signer ID, rather than tracking account changes reactively. The goal is to detect account mismatches without triggering re-renders when the account changes.

Applied to files:

  • examples/spa/src/hooks/use-fast-auth-workflow.ts
📚 Learning: 2025-06-09T09:14:11.981Z
Learnt from: JordiParraCrespo
Repo: Peersyst/near-mobile PR: 342
File: apps/mobile/src/modules/wallet/hooks/use-get-wallet-account-total-balance/use-get-wallet-account-total-balance.ts:26-28
Timestamp: 2025-06-09T09:14:11.981Z
Learning: In the near-mobile project, when calculating derived values from query results in React hooks, use useMemo with proper dependencies (like queryResult.data and fiatPrice.data) to avoid unnecessary re-renders and reference changes. This pattern should be followed consistently across wallet-related hooks to optimize performance.

Applied to files:

  • examples/spa/src/hooks/use-fast-auth-workflow.ts
📚 Learning: 2025-02-27T10:24:14.276Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 58
File: packages/shared/blockchain/core/src/signers/signer.ts:26-27
Timestamp: 2025-02-27T10:24:14.276Z
Learning: The Signer interface uses `Record<string, any>` for the transaction parameter in `signTransaction` method to allow implementing classes to add their own specific types extending this base type, providing flexibility for different blockchain implementations.

Applied to files:

  • apps/account-verifier/src/components/steps/SignTransactionStep.tsx
🧬 Code graph analysis (10)
apps/account-verifier/src/components/LoginButton.tsx (1)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
  • useFastAuth (135-141)
apps/account-verifier/src/components/steps/CreateAccountStep.tsx (1)
packages/shared/cli/src/utils/get-packages-paths.mjs (1)
  • p (12-12)
apps/account-verifier/src/main.tsx (1)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
  • FastAuthProvider (53-133)
apps/account-verifier/src/pages/Home.tsx (3)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
  • useFastAuth (135-141)
apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (1)
  • useFastAuthWorkflow (33-175)
apps/account-verifier/src/hooks/use-access-keys.ts (1)
  • useAccessKeys (36-127)
apps/account-verifier/src/components/LogoutButton.tsx (1)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
  • useFastAuth (135-141)
apps/account-verifier/src/components/steps/LoginStep.tsx (2)
apps/account-verifier/src/components/LogoutButton.tsx (1)
  • LogoutButton (5-23)
apps/account-verifier/src/components/LoginButton.tsx (1)
  • LoginButton (5-23)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (4)
packages/sdks/react/src/core/relayer/relayer.ts (1)
  • FastAuthRelayer (10-102)
packages/providers/javascript/src/provider.ts (1)
  • JavascriptProvider (13-130)
apps/account-verifier/src/services/fast-auth-relayer.ts (1)
  • NetworkId (16-16)
packages/sdks/react/src/providers/utils/contracts.ts (1)
  • getContractsFromNetwork (8-21)
apps/account-verifier/src/components/steps/SignTransactionStep.tsx (1)
packages/shared/cli/src/utils/get-packages-paths.mjs (1)
  • p (12-12)
apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (3)
examples/spa/src/hooks/use-fast-auth-workflow.ts (3)
  • WorkflowState (9-22)
  • WorkflowActions (24-31)
  • useFastAuthWorkflow (33-167)
packages/providers/javascript/src/provider.ts (1)
  • JavascriptProvider (13-130)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
  • useFastAuth (135-141)
apps/account-verifier/src/services/fast-auth-relayer.ts (1)
packages/sdks/react/src/core/relayer/relayer.ts (1)
  • FastAuthRelayer (10-102)
🪛 dotenv-linter (4.0.0)
apps/account-verifier/.env.example

[warning] 1-1: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 2-2: [UnorderedKey] The VITE_RELAYER_ACCOUNT_ID key should go before the VITE_RELAYER_PRIVATE_KEY key

(UnorderedKey)


[warning] 3-3: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 3-3: [UnorderedKey] The VITE_APP_ORIGIN key should go before the VITE_RELAYER_ACCOUNT_ID key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-base / Build
  • GitHub Check: integration-packages / Build
🔇 Additional comments (20)
apps/account-verifier/tsconfig.app.json (1)

1-26: LGTM! Well-configured TypeScript setup for React + Vite.

The configuration follows modern best practices:

  • ES2020 target with DOM libraries is appropriate for browser environments
  • Bundler mode resolution aligns with Vite's build system
  • react-jsx uses the modern JSX transform (React 17+)
  • Comprehensive strict type-checking with additional linting rules
apps/account-verifier/tsconfig.json (1)

1-7: LGTM! Correct TypeScript project references setup.

The configuration properly uses TypeScript's project references pattern, separating app code (tsconfig.app.json) from build tooling (tsconfig.node.json). This enables incremental builds and better IDE support.

apps/account-verifier/tsconfig.node.json (1)

1-24: LGTM! Appropriate Node.js/build tooling configuration.

The configuration correctly targets ES2022/ES2023 for Node.js runtime (where Vite executes), which is intentionally newer than the app configuration's ES2020 target. This allows build tooling to leverage modern Node.js features while maintaining broader browser compatibility for the app code.

apps/account-verifier/.env.example (1)

1-3: Static analysis warnings are false positives.

The dotenv-linter warnings about quote characters and key ordering can be safely ignored:

  • Quotes around empty strings in .env.example files are conventional and harmless.
  • Key ordering is a stylistic preference with no functional impact.
apps/account-verifier/src/App.css (1)

30-34: Good accessibility practice.

The reduced-motion media query respects user preferences, which is excellent for accessibility.

apps/account-verifier/src/polyfills/index.ts (1)

1-1: LGTM!

The Buffer polyfill import is appropriate for browser environments that lack Node.js Buffer API.

examples/spa/src/hooks/use-fast-auth-workflow.ts (1)

3-4: Verify the package renames and API compatibility.

The imports have been updated from @fast-auth/browser and @fast-auth/javascript to @fast-auth/browser-sdk and @fast-auth/javascript-provider. These new packages exist in the monorepo workspace and maintain full API compatibility with all required exports present.

apps/account-verifier/vite.config.ts (1)

1-11: LGTM!

The Vite configuration is appropriate for a React + NEAR app, with node polyfills correctly included to support browser-based NEAR SDK usage.

apps/account-verifier/src/polyfills/buffer/index.ts (1)

1-3: LGTM!

The Buffer polyfill correctly exposes Node.js Buffer globally for browser environments, following the established pattern for global variable setup in this codebase.

apps/account-verifier/src/App.tsx (1)

1-17: LGTM!

The App component provides a clean router setup with appropriate structure.

apps/account-verifier/src/main.tsx (1)

1-14: LGTM!

The bootstrap code correctly follows React 19 patterns, with proper import order (polyfills first), StrictMode wrapping, and FastAuthProvider context setup.

apps/account-verifier/package.json (1)

22-22: React 19.2.0 does not include breaking changes—the breaking changes were in React 19.0.

React 19.2 is not a breaking release; it was released on October 1, 2025 and focuses on performance and new APIs like <Activity> and useEffectEvent. The breaking changes you mentioned (propTypes removal and string refs removal) occurred in React 19.0, not 19.2. React 19.1 also introduced no breaking changes.

For React 19.2.0 specifically, you'll need to upgrade to eslint-plugin-react-hooks@latest so that the linter doesn't try to insert useEffectEvent functions as dependencies. No verification of deprecated patterns is necessary for this version.

Likely an incorrect or invalid review comment.

apps/account-verifier/src/components/steps/index.ts (1)

1-5: LGTM!

Clean barrel export pattern that provides a unified import surface for all step components.

apps/account-verifier/src/components/steps/LoginStep.tsx (1)

15-31: LGTM!

Loading state management follows the established pattern used by LoginButton and LogoutButton, with proper try/finally to ensure state is reset.

apps/account-verifier/src/pages/Home.tsx (1)

7-46: LGTM!

Good structure with proper state management and handler guards. The early returns in handleNetworkChange prevent unnecessary operations when already switching or selecting the same network.

apps/account-verifier/src/components/steps/RequestTransactionStep.tsx (1)

23-45: LGTM!

Clean form submission handling with proper validation, loading state management, and error handling using try/catch/finally.

apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (1)

33-47: LGTM on the hook structure.

The state management and workflow coordination follow the established pattern from the SPA example. The separation of state and actions provides a clean interface for consuming components.

apps/account-verifier/src/hooks/use-access-keys.ts (1)

119-127: LGTM!

The return object cleanly exposes all necessary state and the fetch function for consumers.

apps/account-verifier/src/services/fast-auth-relayer.ts (1)

166-201: LGTM - relaySignAction implementation.

The method correctly constructs a transaction, signs it locally, and sends it via the provider. The SHA-256 hashing and base58 encoding align with NEAR's signing conventions.

apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)

38-51: Duplicated contract mapping logic needs resolution.

The getContractsFromNetwork function duplicates logic from packages/sdks/react/src/providers/utils/contracts.ts, but this function is not currently exported from @fast-auth/browser-sdk, making it inaccessible for import. To eliminate the duplication, either export this utility function from the shared package and import it here, or document why the local implementation is necessary.

"domain": "auth0.aws.peersyst.tech",
"clientId": "qOfA3FaWedmD9LjFS9uRvQVJ0U3XhsgA",
"audience": "fast-auth-api-test-0.com",
"appOrigin": "http://localhost:3000",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make appOrigin environment-specific.

The hardcoded localhost:3000 value will break when deployed to staging or production environments.

Consider using environment variables:

 {
     "domain": "auth0.aws.peersyst.tech",
     "clientId": "qOfA3FaWedmD9LjFS9uRvQVJ0U3XhsgA",
     "audience": "fast-auth-api-test-0.com",
-    "appOrigin": "http://localhost:3000",
+    "appOrigin": "${APP_ORIGIN}",
     "mpcContractId": "v1.signer-prod.testnet",
     "fastAuthContractId": "fast-auth-beta-001.testnet"
 }

Then in your config loader, replace the placeholder with import.meta.env.VITE_APP_ORIGIN or use Vite's environment variable substitution.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/account-verifier/src/auth_config.json around line 5, appOrigin is
hardcoded to "http://localhost:3000"; change it to be environment-specific by
replacing the literal with a placeholder and update the config loader to read
the runtime env (e.g. use import.meta.env.VITE_APP_ORIGIN when using Vite or
process.env.VITE_APP_ORIGIN in Node builds), provide a sensible fallback (e.g.
empty string or default origin) and validate the value before use so
staging/production origins are injected from environment variables.

Comment on lines +13 to +29
<button
onClick={onClick}
style={{
width: "100%",
textAlign: "left",
padding: "1rem",
background: "#181a20",
border: "none",
borderRadius: "8px 8px 0 0",
fontWeight: 600,
cursor: "pointer",
outline: "none",
color: "#f1f1f1",
}}
>
{title}
</button>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add type="button" to prevent unintended form submission.

The button lacks an explicit type attribute, which defaults to "submit" in HTML forms. This can cause unintended form submissions if the Accordion is used inside a form context.

Apply this diff:

             <button
+                type="button"
                 onClick={onClick}
                 style={{
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
onClick={onClick}
style={{
width: "100%",
textAlign: "left",
padding: "1rem",
background: "#181a20",
border: "none",
borderRadius: "8px 8px 0 0",
fontWeight: 600,
cursor: "pointer",
outline: "none",
color: "#f1f1f1",
}}
>
{title}
</button>
<button
type="button"
onClick={onClick}
style={{
width: "100%",
textAlign: "left",
padding: "1rem",
background: "#181a20",
border: "none",
borderRadius: "8px 8px 0 0",
fontWeight: 600,
cursor: "pointer",
outline: "none",
color: "#f1f1f1",
}}
>
{title}
</button>
🤖 Prompt for AI Agents
In apps/account-verifier/src/components/Accordion.tsx around lines 13 to 29, the
clickable button element lacks an explicit type and will default to
type="submit" when placed inside a form; update the button to include
type="button" to prevent unintended form submissions, keeping the existing props
(onClick, style, children) unchanged.

Comment on lines +9 to +16
const handleLogin = async () => {
setIsLoading(true);
try {
await client?.login();
} finally {
setIsLoading(false);
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add error handling and user feedback for login failures.

The login flow has two reliability gaps:

  1. If client is null, the login silently does nothing due to optional chaining
  2. Login errors are caught but not displayed to the user

Apply this diff to add error feedback:

 const LoginButton = () => {
     const { client } = useFastAuth();
     const [isLoading, setIsLoading] = useState(false);
+    const [error, setError] = useState<string | null>(null);

     const handleLogin = async () => {
+        if (!client) {
+            setError("Authentication client not initialized");
+            return;
+        }
         setIsLoading(true);
+        setError(null);
         try {
-            await client?.login();
+            await client.login();
+        } catch (err) {
+            setError(err instanceof Error ? err.message : "Login failed");
         } finally {
             setIsLoading(false);
         }
     };

     return (
-        <button onClick={handleLogin} disabled={isLoading}>
-            {isLoading ? <Spinner size={18} /> : "Log in"}
-        </button>
+        <div>
+            <button onClick={handleLogin} disabled={isLoading}>
+                {isLoading ? <Spinner size={18} /> : "Log in"}
+            </button>
+            {error && <p style={{ color: "red" }}>Error: {error}</p>}
+        </div>
     );
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +9 to +16
const handleLogout = async () => {
setIsLoading(true);
try {
await client?.logout();
} finally {
setIsLoading(false);
}
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add error handling for logout failures.

The logout call has no error handling. If client.logout() throws an error, it will be unhandled and the user won't receive feedback about the failure.

Apply this diff to handle errors appropriately:

     const handleLogout = async () => {
         setIsLoading(true);
         try {
             await client?.logout();
+        } catch (error) {
+            console.error("Logout failed:", error);
+            // Consider showing a user-facing error message
+            // e.g., toast notification or alert
         } finally {
             setIsLoading(false);
         }
     };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleLogout = async () => {
setIsLoading(true);
try {
await client?.logout();
} finally {
setIsLoading(false);
}
};
const handleLogout = async () => {
setIsLoading(true);
try {
await client?.logout();
} catch (error) {
console.error("Logout failed:", error);
// Consider showing a user-facing error message
// e.g., toast notification or alert
} finally {
setIsLoading(false);
}
};
🤖 Prompt for AI Agents
In apps/account-verifier/src/components/LogoutButton.tsx around lines 9 to 16,
the logout call lacks error handling so exceptions from client.logout() are
unhandled; wrap the await client?.logout() in a try/catch/finally, in the catch
capture the error, log it (console.error or a logger) and surface user feedback
(set an error state or call the existing toast/notification API) so the user
knows logout failed, and keep setIsLoading(false) in the finally block to ensure
loading state is cleared.

Comment on lines +20 to +23
// Add keyframes for spin animation
const style = document.createElement("style");
style.innerHTML = `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`;
document.head.appendChild(style);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Move animation injection inside component or to a CSS file.

The module-level DOM mutation creates side effects at import time, which can cause duplicate <style> elements if the module is imported multiple times or fails in SSR contexts.

Consider one of these approaches:

Option 1: Use useEffect to inject once

+import React, { useEffect } from "react";
+
+let animationInjected = false;
+
 const Spinner: React.FC<{ size?: number }> = ({ size = 18 }) => {
+    useEffect(() => {
+        if (!animationInjected && !document.querySelector('style[data-spinner-animation]')) {
+            const style = document.createElement("style");
+            style.setAttribute('data-spinner-animation', 'true');
+            style.innerHTML = `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`;
+            document.head.appendChild(style);
+            animationInjected = true;
+        }
+    }, []);
+
     <span
         style={{

Option 2: Move to a CSS file

Create Spinner.css:

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

Then import it:

 import React from "react";
+import "./Spinner.css";
-
-// Add keyframes for spin animation
-const style = document.createElement("style");
-style.innerHTML = `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`;
-document.head.appendChild(style);
🤖 Prompt for AI Agents
In apps/account-verifier/src/components/Spinner.tsx around lines 20-23, the
module-level DOM mutation injects a <style> tag at import time which causes
duplicate styles and breaks SSR; move this logic into the component (inject once
inside a useEffect with a guard to avoid duplicate insertion) or, preferably,
create a Spinner.css with the @keyframes spin and import that CSS from the
component, then remove the
document.createElement/style.innerHTML/document.head.appendChild code from the
module scope.

Comment on lines +57 to +63
span {
color: #000;
}

li {
color: #000;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix dark mode text color for span and li elements.

Hardcoding color: #000 (black) on span and li elements will make them nearly invisible against the dark background (#242424) in dark mode, severely impacting readability.

Apply this diff to make these elements respect the color scheme:

 span {
-    color: #000;
+    color: inherit;
 }
 
 li {
-    color: #000;
+    color: inherit;
 }
 
 @media (prefers-color-scheme: light) {
     :root {
         color: #213547;
         background-color: #ffffff;
     }
     a:hover {
         color: #747bff;
     }
     button {
         background-color: #f9f9f9;
     }
+    span,
+    li {
+        color: #000;
+    }
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/account-verifier/src/index.css around lines 57 to 63, the span and li
rules currently hardcode color: #000 which breaks readability in dark mode;
change these rules so they don't force black — use a theme-aware value such as
color: inherit or color: var(--text-color, currentColor) (or currentColor) so
they follow the page/root text color or CSS variable used for light/dark themes;
update the CSS to remove the hardcoded #000 and reference the appropriate
variable/inherit behavior.

Comment on lines +34 to +54
.info-label {
font-weight: 500;
color: #bbb;
}

input {
background-color: #181a20;
color: #e0e0e0;
border: 1px solid #222;
border-radius: 4px;
padding: 0.5rem;
width: 100%;
max-width: 300px;
}

.info-label {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin: 0.5rem 0;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Duplicate .info-label selector causing style override.

The .info-label class is defined twice (lines 34-37 and 49-54). The second definition will completely override the first, losing the font-weight and color properties. Merge these into a single definition.

Apply this diff to merge the definitions:

 .info-label {
     font-weight: 500;
     color: #bbb;
-}
-
-input {
-    background-color: #181a20;
-    color: #e0e0e0;
-    border: 1px solid #222;
-    border-radius: 4px;
-    padding: 0.5rem;
-    width: 100%;
-    max-width: 300px;
-}
-
-.info-label {
     display: flex;
     flex-direction: column;
     gap: 0.5rem;
     margin: 0.5rem 0;
 }
+
+input {
+    background-color: #181a20;
+    color: #e0e0e0;
+    border: 1px solid #222;
+    border-radius: 4px;
+    padding: 0.5rem;
+    width: 100%;
+    max-width: 300px;
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.info-label {
font-weight: 500;
color: #bbb;
}
input {
background-color: #181a20;
color: #e0e0e0;
border: 1px solid #222;
border-radius: 4px;
padding: 0.5rem;
width: 100%;
max-width: 300px;
}
.info-label {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin: 0.5rem 0;
}
.info-label {
font-weight: 500;
color: #bbb;
display: flex;
flex-direction: column;
gap: 0.5rem;
margin: 0.5rem 0;
}
input {
background-color: #181a20;
color: #e0e0e0;
border: 1px solid #222;
border-radius: 4px;
padding: 0.5rem;
width: 100%;
max-width: 300px;
}
🤖 Prompt for AI Agents
In apps/account-verifier/src/pages/Home.css around lines 34 to 54, the
.info-label selector is declared twice so the second block overrides the first
and drops font-weight and color; merge the two blocks into a single .info-label
rule that includes font-weight: 500, color: #bbb, display: flex, flex-direction:
column, gap: 0.5rem, and margin: 0.5rem 0, then remove the duplicate
declaration.

Comment on lines +12 to +29
// Environment variables for relayer configuration
const RELAYER_PRIVATE_KEY = import.meta.env.VITE_RELAYER_PRIVATE_KEY;
const RELAYER_ACCOUNT_ID = import.meta.env.VITE_RELAYER_ACCOUNT_ID;
// Contract IDs will be determined by network
export type NetworkId = "testnet" | "mainnet";

const getFastAuthContractId = (networkId: NetworkId): string => {
return networkId === "mainnet" ? "fast-auth.near" : "fast-auth-beta-001.testnet";
};

// Validate required environment variables
if (!RELAYER_PRIVATE_KEY) {
throw new Error("VITE_RELAYER_PRIVATE_KEY environment variable is required. Please create a .env file with your relayer credentials.");
}

if (!RELAYER_ACCOUNT_ID) {
throw new Error("VITE_RELAYER_ACCOUNT_ID environment variable is required. Please create a .env file with your relayer credentials.");
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Module-level throw blocks application startup.

Throwing at module load time will crash the entire application if environment variables are missing, even for routes/components that don't use this service. Consider lazy validation in init() or constructor.

 // Environment variables for relayer configuration
 const RELAYER_PRIVATE_KEY = import.meta.env.VITE_RELAYER_PRIVATE_KEY;
 const RELAYER_ACCOUNT_ID = import.meta.env.VITE_RELAYER_ACCOUNT_ID;
 // Contract IDs will be determined by network
 export type NetworkId = "testnet" | "mainnet";

 const getFastAuthContractId = (networkId: NetworkId): string => {
     return networkId === "mainnet" ? "fast-auth.near" : "fast-auth-beta-001.testnet";
 };

-// Validate required environment variables
-if (!RELAYER_PRIVATE_KEY) {
-    throw new Error("VITE_RELAYER_PRIVATE_KEY environment variable is required. Please create a .env file with your relayer credentials.");
-}
-
-if (!RELAYER_ACCOUNT_ID) {
-    throw new Error("VITE_RELAYER_ACCOUNT_ID environment variable is required. Please create a .env file with your relayer credentials.");
-}

Then validate in init():

async init() {
    if (!RELAYER_PRIVATE_KEY) {
        throw new Error("VITE_RELAYER_PRIVATE_KEY environment variable is required.");
    }
    if (!RELAYER_ACCOUNT_ID) {
        throw new Error("VITE_RELAYER_ACCOUNT_ID environment variable is required.");
    }
    // ... rest of init
}
🤖 Prompt for AI Agents
In apps/account-verifier/src/services/fast-auth-relayer.ts around lines 12 to
29, the module currently throws errors during import when RELAYER_PRIVATE_KEY or
RELAYER_ACCOUNT_ID are missing which crashes the whole app; remove these
top-level throws and instead perform the same validations inside an async init()
(or the service constructor) so missing env variables are detected only when the
relayer is actually initialized—move the error messages into init(), throw there
if values are falsy, and keep the RELAYER_* constants available for lazy checks;
ensure no other code relies on the module to throw at load time.

Comment on lines +128 to +143
async createAccount(action: Action) {
try {
const signerPublicKey = this.keyPair.getPublicKey();
const accessKey = (await this.getConnection().connection.provider.query(
`access_key/${this.accountId}/${signerPublicKey}`,
"",
)) as AccessKeyView;
const nonce = ++accessKey.nonce;

const tx = createTransaction(this.accountId, signerPublicKey, this.networkId, nonce, [action], base_decode(accessKey.block_hash));
await this.account.signAndSendTransaction(tx);
} catch (error) {
console.error("Error creating account:", error);
throw error;
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix signAndSendTransaction call to pass options object instead of Transaction object.

The signAndSendTransaction method expects { receiverId, actions } but is being called with a Transaction object. Change to:

await this.account.signAndSendTransaction({ receiverId: this.accountId, actions: [action] });
🤖 Prompt for AI Agents
In apps/account-verifier/src/services/fast-auth-relayer.ts around lines 128 to
143, the code builds a Transaction and calls
this.account.signAndSendTransaction(tx) but signAndSendTransaction expects an
options object ({ receiverId, actions }) not a Transaction; remove the manual
Transaction creation and related access_key query/nonce logic and replace the
call with await this.account.signAndSendTransaction({ receiverId:
this.accountId, actions: [action] }) so the account API handles signing and
sending correctly.

Comment on lines +203 to +213
async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction) {
const signedTransaction = new SignedTransaction({
transaction: tx,
signature: new Signature({
keyType: KeyType.SECP256K1,
data: signature,
}),
});

return await this.getConnection().connection.provider.sendTransaction(signedTransaction);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hardcoded SECP256K1 key type may not match all signatures.

The send method hardcodes KeyType.SECP256K1, but the signature type should match the key type used to create it. If the transaction was signed with an ED25519 key (common for NEAR), this will fail verification.

Consider passing the key type as a parameter or inferring it from the transaction's signer public key:

-    async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction) {
+    async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction, keyType: KeyType = KeyType.SECP256K1) {
         const signedTransaction = new SignedTransaction({
             transaction: tx,
             signature: new Signature({
-                keyType: KeyType.SECP256K1,
+                keyType,
                 data: signature,
             }),
         });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction) {
const signedTransaction = new SignedTransaction({
transaction: tx,
signature: new Signature({
keyType: KeyType.SECP256K1,
data: signature,
}),
});
return await this.getConnection().connection.provider.sendTransaction(signedTransaction);
}
async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction, keyType: KeyType = KeyType.SECP256K1) {
const signedTransaction = new SignedTransaction({
transaction: tx,
signature: new Signature({
keyType,
data: signature,
}),
});
return await this.getConnection().connection.provider.sendTransaction(signedTransaction);
}
🤖 Prompt for AI Agents
In apps/account-verifier/src/services/fast-auth-relayer.ts around lines 203-213
the Signature is hardcoded to KeyType.SECP256K1 which can break verification for
transactions signed with other key types (e.g. ED25519); change the method to
accept a keyType parameter (or infer it from the transaction signer public key)
and use that value when constructing new Signature, or map/infer the correct
KeyType enum before creating SignedTransaction, and add a small validation/error
if the keyType is unsupported.

@AdriaCarrera AdriaCarrera merged commit d513338 into main Dec 17, 2025
8 checks passed
@AdriaCarrera AdriaCarrera deleted the account-verifier branch December 17, 2025 15:26
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.

2 participants

Comments