Skip to content

feat: rebuild live payment network explorer - #2628

Draft
0xkkonrad wants to merge 4 commits into
devfrom
feat/payment-network-explorer
Draft

feat: rebuild live payment network explorer#2628
0xkkonrad wants to merge 4 commits into
devfrom
feat/payment-network-explorer

Conversation

@0xkkonrad

@0xkkonrad 0xkkonrad commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Replaces the shared-password payment graph with a team-authenticated explorer backed only by the canonical live payment-network.v2 API.
  • Adds bounded UTC time windows, rail/method/provider/state filters, signed focus search, graph + relationship table + inspector, and audited step-up reveal.
  • Prevents graph duplication and leakage: no client persistence/export, NetworkOnly + legacy cache purge, no-store, no referrers, and route-level GA/PostHog/Sentry/CSP-report suppression.

Task

TASK-21220

Cross-repo / deploy order

⚠️ The paired peanut-api-ts PR is still pending. Deploy the backend contract before this UI; the explorer intentionally rejects a missing/mismatched contract instead of falling back to the legacy graph.

Backend deployment must configure PAYMENT_NETWORK_TEAM_USER_IDS, PAYMENT_NETWORK_REVEAL_USER_IDS, and PAYMENT_NETWORK_TOKEN_SECRET. The browser exchanges the normal app bearer once for a short-lived Secure HttpOnly session; graph/focus/reveal requests then use that cookie only. Full-graph delivery remains disabled unless the backend benchmark gates pass, so deterministic server sampling is the safe default.

Design notes / accepted trade-offs

  • Desktop-only for v1; mobile receives a guard before any graph request.
  • Native-asset buckets only; no cross-currency total.
  • Graph, table, and inspector reference the same canonical response objects. Hub segments are view projections, not copied relationships.
  • No graph payload enters local/session storage, CacheStorage, analytics, logs, or downloadable artifacts.

QA

  • prettier --check .
  • npm run typecheck
  • npm test -- --runInBand ✅ — 222 suites, 2,745 passed, 3 skipped
  • Local production build: ⚠️ blocked only by the host's earlyoom pressure; remote CI/Preview is the authoritative build gate.
  • Production-preview synthetic browser acceptance: pending Preview URL (headers, zero telemetry, SW purge, BFCache, keyboard/tooltip/focus/reduced-motion/mobile/canonical parity, 5 warmups + 20 runs at 4× CPU).

Screenshots

⚠️ Pending synthetic-only production Preview capture. No live graph response will be captured or attached.

Summary by CodeRabbit

  • New Features

    • Added a payment network explorer with interactive graph and table views.
    • Search users, filter by date, status, payment details, and infrastructure.
    • Inspect nodes and relationships with summaries, health indicators, sorting, pagination, and tooltips.
    • Added audited, time-limited identity reveals for eligible nodes.
    • Added desktop-only guidance and reduced-motion support.
  • Bug Fixes

    • Prevented sensitive explorer data from being cached or indexed.
    • Disabled analytics and error reporting on private explorer routes.
    • Production access to development tools now requires authentication.

@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview Aug 6, 2026 7:34pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1dd6a604-fda9-4172-a5c8-cd6ebb53cf9d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The pull request adds a server-rendered payment-network explorer with typed API access, filtering, graph and table views, inspection, search, and temporary reveals. It also adds route-scoped privacy controls for analytics, Sentry, CSP reports, caching, headers, and production access.

Changes

Payment Network Explorer

Layer / File(s) Summary
Explorer contracts and data flow
src/features/payment-network-explorer/types.ts, query.ts, api.ts, selectors.ts, format.ts, usePaymentNetworkExplorer.ts, useExplorerUrlState.ts, src/features/payment-network-explorer/__tests__/*
Adds typed explorer contracts, validated query construction, no-store API requests, session renewal, graph selectors, formatting helpers, and related tests.
Explorer interface and interaction flow
src/app/(mobile-ui)/dev/payment-graph/page.tsx, src/features/payment-network-explorer/*, src/features/payment-network-explorer/__tests__/*, tailwind.config.js
Replaces the former page with PaymentNetworkExplorer. Adds filters, search, graph and table views, inspection, reveals, responsive behavior, reduced-motion handling, state panels, and accessibility-focused UI tests.
Privacy, access, and telemetry boundaries
instrumentation-client.ts, sentry*.config.ts, sentry.utils.ts, next.config.js, src/app/layout.tsx, src/app/sw.ts, src/app/payment-network-sw-privacy.ts, src/features/payment-network-explorer/privacy*.ts, src/constants/routes.ts, src/utils/csp-report.utils.ts, src/**/*test*
Disables or filters telemetry on explorer routes, prevents sensitive cache storage, removes CSP report forwarding, applies restrictive headers, and requires production access checks.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant PaymentNetworkExplorer
  participant ExplorerAPI
  participant Sentry
  participant PostHog
  Browser->>PaymentNetworkExplorer: open payment-network explorer route
  PaymentNetworkExplorer->>PostHog: suppress capture and recording
  PaymentNetworkExplorer->>Sentry: stop replay and close client
  PaymentNetworkExplorer->>ExplorerAPI: request session and network data
  ExplorerAPI-->>PaymentNetworkExplorer: return typed explorer response
Loading

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: kushagrasarathe

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.96% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: rebuilding the live payment network explorer.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/payment-network-explorer

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

❤️ Share

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

@0xkkonrad

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🧹 Nitpick comments (22)
src/features/payment-network-explorer/query.ts (1)

104-117: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Normalize states like the other list filters.

Every other list field passes through sanitizeFilterValues, which dedupes and sorts. states only filters. Two equal filter selections in different order therefore produce different request keys in usePaymentNetworkExplorer and different query strings, which causes redundant fetches and sends duplicate values to the API.

♻️ Proposed normalization
-        states: filters.states.filter(isMovementState),
+        states: Array.from(new Set(filters.states.filter(isMovementState))).sort(),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/query.ts` around lines 104 - 117,
Update the states field in the returned filter object to pass through
sanitizeFilterValues while preserving isMovementState validation, so states are
filtered, deduplicated, and sorted consistently with the other list filters.
Keep the existing normalized state values and request-key behavior for valid
selections.
src/features/payment-network-explorer/selectors.ts (1)

94-107: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Reuse one Intl.Collator for string comparisons.

localeCompare creates collation state on each call. RelationshipTable sorts up to 5000 relationships (the request limit) on every sort change and every response, so this runs on the render path. A module-level collator removes that per-comparison cost.

♻️ Proposed collator reuse
+const relationshipCollator = new Intl.Collator('en-US')
+
 export function sortRelationships(
@@
         if (typeof a === 'number' && typeof b === 'number') return (a - b) * multiplier
-        return String(a).localeCompare(String(b)) * multiplier
+        return relationshipCollator.compare(String(a), String(b)) * multiplier
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/selectors.ts` around lines 94 - 107,
Update sortRelationships to reuse a single module-level Intl.Collator for string
comparisons instead of calling localeCompare directly on each sort comparison.
Keep numeric sorting and direction handling unchanged, and use the shared
collator in the non-numeric branch.
src/features/payment-network-explorer/usePaymentNetworkExplorer.ts (1)

182-182: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Wrap reload in useCallback.

reload is a new function on every render. Consumers that memoize on this prop re-render on each parent render.

♻️ Proposed refactor
+    const reload = useCallback(() => setReloadKey((value) => value + 1), [])
+
     return {
         data,
         session,
         status,
         error,
         searching,
         revealing,
-        reload: () => setReloadKey((value) => value + 1),
+        reload,
         focusUsername,
         revealNode,
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/usePaymentNetworkExplorer.ts` at line
182, Wrap the reload function in usePaymentNetworkExplorer with useCallback so
its reference remains stable across renders, using setReloadKey as its
dependency and preserving the existing increment behavior.
src/features/payment-network-explorer/__tests__/query.test.ts (1)

33-38: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add the accepted 120-day boundary case.

This assertion covers only the rejected side of the maximum window. The exact 120-day window is the boundary most likely to regress from an off-by-one change in the resolver.

💚 Proposed addition
         expect(() =>
             resolveExplorerWindow(
                 { range: 'custom', customFrom: '2026-04-07T11:59:59.999Z', customTo: NOW.toISOString() },
                 NOW
             )
         ).toThrow(ExplorerWindowError)
+        expect(
+            resolveExplorerWindow(
+                { range: 'custom', customFrom: '2026-04-08T12:00:00.000Z', customTo: NOW.toISOString() },
+                NOW
+            )
+        ).toEqual({ from: '2026-04-08T12:00:00.000Z', to: NOW.toISOString() })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/__tests__/query.test.ts` around lines
33 - 38, Add a test near the existing resolveExplorerWindow maximum-window
rejection assertion that passes a custom range exactly 120 days before NOW
through NOW and expects successful resolution. Keep the current over-limit case
unchanged, using the existing resolveExplorerWindow and NOW symbols to cover the
accepted boundary.
src/app/sw.ts (1)

24-38: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move the PostHog /relay/ explanation above the /relay/ rule.

Lines 27-31 describe the PostHog reverse-proxy path and the no-response errors on recorder scripts. That text now sits above the payment-network rule, which has its own comment at Lines 34-35. A reader attributes the PostHog rationale to the wrong matcher.

♻️ Proposed change
     // A controlled service worker sees cross-origin fetches initiated by its
     // clients. Keep privacy-sensitive API routes ahead of every default rule.
-    //
-    // /relay/* is the PostHog reverse-proxy path (see next.config.js rewrites).
-    // Workbox's defaultCache strategies threw "no-response" on the recorder +
-    // dead-clicks scripts, polluting the console. PostHog assets carry their
-    // own versioning + cache headers; let the network handle them. NetworkOnly
-    // first so it wins ahead of any defaultCache JS-asset rule.
     runtimeCaching: [
         {
             // Covers the protected document/RSC path on peanut.me and every
             // legacy/v2 graph endpoint across API origins, regardless of query.
             matcher: ({ url }) => isSensitivePaymentNetworkUrl(url),
             handler: new NetworkOnly(),
         },
         {
+            // /relay/* is the PostHog reverse-proxy path (see next.config.js
+            // rewrites). Workbox's defaultCache strategies threw "no-response"
+            // on the recorder + dead-clicks scripts, polluting the console.
+            // PostHog assets carry their own versioning + cache headers; let
+            // the network handle them. NetworkOnly wins ahead of any
+            // defaultCache JS-asset rule.
             matcher: ({ url }) => url.pathname.startsWith('/relay/'),
             handler: new NetworkOnly(),
         },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/sw.ts` around lines 24 - 38, Move the PostHog `/relay/` explanation
so it immediately precedes the runtime-caching rule whose matcher handles
`/relay/` requests, keeping the payment-network rule’s comment directly attached
to `isSensitivePaymentNetworkUrl` and leaving rule behavior unchanged.
src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx (3)

169-171: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore the spies in afterEach so a failed assertion does not leak them.

The console spies are restored at the end of the test body (Lines 192-194). If any assertion between Lines 180-191 fails, the test aborts and the spies stay installed. Later tests in this file then run with a silenced console. The Date.now spy at Line 198 has the same problem, since it is restored at Line 243.

Move the restoration into afterEach, or add restoreMocks: true to the Jest config.

♻️ Proposed change
     afterEach(() => {
+        jest.restoreAllMocks()
         window.history.replaceState({}, '', '/')
     })

Note that jest.restoreAllMocks() also resets the jest.mocked(...) implementations set in beforeEach; since beforeEach re-applies them on every test, the order remains correct.

Also applies to: 192-194

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx`
around lines 169 - 171, Update the PaymentNetworkExplorer test setup to restore
all spies in an afterEach hook, including the console spies created in the test
and the Date.now spy. Remove the inline restoration from the test body, and
ensure beforeEach mock setup still runs after restoration for each test.

197-244: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Expose document.visibilityState in the synthetic visibilitychange test.

The clearExpiredReveal handler does not gate on document.visibilityState, but line 228 still does not set it to 'hidden'. Set document.visibilityState to 'hidden' in jsdom before dispatching visibilitychange so the test is not accidental if a visibility guard is added later.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx`
around lines 197 - 244, Update the visibilitychange portion of the test case
“clears privileged reveals on background resume and pagehide” to set
document.visibilityState to 'hidden' before dispatching the synthetic
visibilitychange event, preserving the existing expiration and reveal
assertions.

169-194: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Every new test file cleans up global state at the end of the test body. The shared root cause is that cleanup is not registered with afterEach or finally. A failed assertion or a thrown require skips the cleanup, and the mutated global leaks into the remaining tests in the same Jest worker. Enabling restoreMocks: true in the Jest config removes the spy half of this problem for all four files.

  • src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx#L169-L194: move the console.log, console.warn, console.error, and Date.now restorations into the existing afterEach.
  • src/features/payment-network-explorer/__tests__/headers.test.ts#L3-L21: restore LOCAL_BUILD, NODE_ENV, and the console.log spy in an afterEach block.
  • src/features/payment-network-explorer/__tests__/privacy.test.ts#L84-L94: restore the document.head.appendChild spy in an afterEach block instead of at Line 92.
  • src/features/payment-network-explorer/__tests__/sentryServerEdge.test.ts#L37-L43: restore NODE_ENV in a finally block around the jest.isolateModules call.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx`
around lines 169 - 194, Register global cleanup outside test bodies so failures
cannot leak state: in
src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx#L169-L194,
move console.log, console.warn, console.error, and Date.now restoration into the
existing afterEach; in
src/features/payment-network-explorer/__tests__/headers.test.ts#L3-L21, restore
LOCAL_BUILD, NODE_ENV, and the console.log spy in afterEach; in
src/features/payment-network-explorer/__tests__/privacy.test.ts#L84-L94, move
document.head.appendChild restoration into afterEach; and in
src/features/payment-network-explorer/__tests__/sentryServerEdge.test.ts#L37-L43,
restore NODE_ENV in a finally block surrounding jest.isolateModules. Enable
restoreMocks in the Jest configuration to provide automatic spy restoration.
src/features/payment-network-explorer/__tests__/privacy.test.ts (1)

84-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Suppress the scanner finding on new Function, and restore the spy in afterEach.

OpenGrep flags Line 88 as dynamic code execution. The input comes from the project's own googleAnalyticsBootstrapScript, so the finding is a false positive for this test. Add an inline suppression so the rule does not stay noisy on this file.

Separately, append.mockRestore() at Line 92 runs only if the assertions at Lines 90-91 pass. jest.clearAllMocks() in beforeEach clears calls but does not restore the spy, so a failure leaves document.head.appendChild patched for later tests.

♻️ Proposed change
         const append = jest.spyOn(document.head, 'appendChild')
         const script = googleAnalyticsBootstrapScript('G-QATEST')
+        // nosemgrep: coderabbit.code-injection.new-function-js -- the script is
+        // generated by googleAnalyticsBootstrapScript, not by external input.
         new Function('window', 'document', 'location', script)(window, document, window.location)
 
         expect((window as unknown as Window & Record<string, unknown>)['ga-disable-G-QATEST']).toBe(true)
         expect(append).not.toHaveBeenCalled()
-        append.mockRestore()
         window.history.replaceState({}, '', '/')

Add the restoration to the suite:

+    afterEach(() => {
+        jest.restoreAllMocks()
+    })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/__tests__/privacy.test.ts` around lines
84 - 94, Add an inline OpenGrep suppression for the dynamic execution at `new
Function` in the direct legacy URL test, documenting it as a false positive for
the trusted `googleAnalyticsBootstrapScript` output. Move spy cleanup to the
suite’s `afterEach` so `document.head.appendChild` is restored even when
assertions fail, and remove the test-local `append.mockRestore()` to avoid
duplicate cleanup.

Source: Linters/SAST tools

src/features/payment-network-explorer/Inspector.tsx (1)

171-172: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Memoize the connection list and show when it is truncated.

relationshipsForNode scans all relationships on every Inspector render, and .slice(0, 100) drops the remainder with no indication in the UI. Wrap the computation in useMemo, and render a count when connections exceed the limit.

♻️ Proposed refactor
+    const nodeRelationships = useMemo(
+        () => (selection?.type === 'node' ? relationshipsForNode(relationships, selection.node.id) : []),
+        [relationships, selection]
+    )

Then render nodeRelationships.slice(0, 100) in the list, and add a trailing note when nodeRelationships.length > 100.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/Inspector.tsx` around lines 171 - 172,
In the Inspector component, memoize the result of
relationshipsForNode(relationships, selection.node.id) as nodeRelationships with
useMemo and appropriate dependencies. Render nodeRelationships.slice(0, 100) in
the connection list, and add a trailing UI note indicating the number of
additional connections when nodeRelationships.length exceeds 100.
tailwind.config.js (1)

16-16: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a general src/features glob.

The new entry covers one feature directory. Every later feature under src/features will need another entry, and a missing entry produces silently unstyled components. './src/features/**/*.{js,ts,jsx,tsx,mdx}' covers the whole directory and matches the pattern of the entries above it.

-        './src/features/payment-network-explorer/**/*.{js,ts,jsx,tsx}',
+        './src/features/**/*.{js,ts,jsx,tsx,mdx}',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tailwind.config.js` at line 16, Update the Tailwind content configuration
entry for the payment-network-explorer feature to use the general src/features
glob './src/features/**/*.{js,ts,jsx,tsx,mdx}', covering all current and future
feature directories while preserving the existing extensions.
src/features/payment-network-explorer/PaymentNetworkExplorer.tsx (1)

58-85: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider replacing the JSON round trip with a normal memo.

requestFilterKey serializes the filters only to have Line 76 parse them back. The round trip stabilizes the memo across new array identities, but it hides that intent and it allocates two objects plus a string on every render. A memo over the individual filter fields expresses the same dependency set directly.

-    const requestResult = useMemo(() => {
-        const requestFilters = JSON.parse(requestFilterKey) as ExplorerFilters
         try {

If you keep the current form, add a short comment that states why the key is serialized.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/PaymentNetworkExplorer.tsx` around
lines 58 - 85, Replace the requestFilterKey JSON serialization and parsing in
the requestResult useMemo with direct references to the individual filter
fields, using those fields as the memo dependency set while preserving the
existing buildExplorerRequest and error-handling behavior. Keep the request
filters equivalent to the current ExplorerFilters object and remove the
unnecessary serialization round trip.
src/features/payment-network-explorer/__tests__/reducedMotion.test.tsx (1)

28-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add coverage for a runtime preference change.

mockMatchMedia stubs addEventListener with a jest.fn() that never calls the listener. The test at Line 52 therefore only covers the initial read in useReducedMotion. The change subscription and the listener cleanup at useReducedMotion.ts Lines 14-15 stay untested. Capture the listener in the mock and invoke it, so a preference change is asserted to update the hook result.

💚 Proposed test addition
 function mockMatchMedia(matches: boolean) {
+    const listeners = new Set<() => void>()
     window.matchMedia = jest.fn(
         () =>
             ({
                 matches,
                 media: '(prefers-reduced-motion: reduce)',
                 onchange: null,
-                addEventListener: jest.fn(),
-                removeEventListener: jest.fn(),
+                addEventListener: jest.fn((_: string, listener: () => void) => listeners.add(listener)),
+                removeEventListener: jest.fn((_: string, listener: () => void) => listeners.delete(listener)),
                 addListener: jest.fn(),
                 removeListener: jest.fn(),
                 dispatchEvent: jest.fn(),
             }) as unknown as MediaQueryList
     )
+    return listeners
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/__tests__/reducedMotion.test.tsx`
around lines 28 - 55, Update mockMatchMedia and the reduced-motion test to
capture the change listener registered through addEventListener, then invoke it
with an updated matches value and assert useReducedMotion reflects the
preference change. Also exercise unmounting so the removeEventListener cleanup
in useReducedMotion is covered.
src/app/api/csp-report/__tests__/route.test.ts (1)

26-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a positive control, and cover script-src-elem and script-src-attr.

Both cases assert mockedFetch was not called. The route returns 204 without forwarding for several unrelated reasons, including an unaccepted content type and an empty report list. If a future change stops forwarding every report, this suite still passes and the explorer-privacy guarantee is no longer proven.

Add a case with a non-explorer document-uri that asserts mockedFetch was called. Also extend the fixtures beyond the bare script-src directive: browsers report inline scripts as script-src-elem and inline handlers as script-src-attr.

💚 Proposed test addition
+    it('forwards a non-explorer report', async () => {
+        const request = {
+            headers: new Headers({ 'content-type': 'application/csp-report' }),
+            json: jest.fn().mockResolvedValue({
+                'csp-report': {
+                    'document-uri': 'https://peanut.me/card',
+                    'blocked-uri': 'https://blocked.example/script.js',
+                    'effective-directive': 'script-src-elem',
+                },
+            }),
+        } as unknown as NextRequest
+
+        expect((await POST(request)).status).toBe(204)
+        expect(mockedFetch).toHaveBeenCalledTimes(1)
+    })

Based on learnings: in the CSP reporting pipeline, aggregation and handling tests must cover both script-src-elem and script-src-attr, not only script-src.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/api/csp-report/__tests__/route.test.ts` around lines 26 - 61,
Strengthen the CSP report route tests around the parameterized fixtures by
adding a non-explorer document URI case that expects mockedFetch to be called,
proving eligible reports are forwarded. Add coverage for script-src-elem and
script-src-attr in both supported report formats while retaining the existing
explorer-privacy assertions that expect no forwarding.

Source: Learnings

src/app/payment-network-sw-privacy.ts (1)

1-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Share the explorer API path for service-worker privacy checks.

src/app/payment-network-sw-privacy.ts keeps a separate PAYMENT_GRAPH_API_PATH = '/invites/graph' copy from the explorer API callers. Use one shared constant across the service worker and payment-network-explorer callers so a route rename cannot disable cache purging while leaving API paths enabled.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/payment-network-sw-privacy.ts` around lines 1 - 11, The payment graph
API path is duplicated in isSensitivePaymentNetworkPathname; replace the local
PAYMENT_GRAPH_API_PATH with the shared explorer API-path constant used by
payment-network-explorer callers, updating imports or exports as needed.
Preserve both exact and trailing-subpath checks so privacy handling remains
unchanged after route renames.
src/features/payment-network-explorer/FilterPanel.tsx (1)

184-190: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Narrow the direction values instead of casting.

Line 189 casts the incoming string[] to ExplorerFilters['directions']. The values come from server facets, so an unexpected value passes the type system unchecked. Filter against the known direction union before calling onChange.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/FilterPanel.tsx` around lines 184 -
190, Update the Direction FacetChecklist onChange handler to filter incoming
strings against the known ExplorerFilters direction union before calling
onChange, instead of casting the entire array. Preserve only valid direction
values and pass that narrowed collection to onChange.
sentry.utils.ts (1)

5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Move the payment-graph route into shared route constants.

src/constants/routes.ts only lists /dev as a dev-route pattern and does not export PAYMENT_NETWORK_PATH. Add the explicit /dev/payment-graph constant there and use it from sentry.utils.ts, privacy-route.ts, and other route code that hard-code this path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sentry.utils.ts` at line 5, Move the /dev/payment-graph path into the shared
route constants by adding and exporting a PAYMENT_NETWORK_PATH symbol in
routes.ts, then replace hard-coded path values and local definitions in
sentry.utils.ts, privacy-route.ts, and other route code with that shared
constant while preserving existing route-matching behavior.
src/features/payment-network-explorer/FacetChecklist.tsx (1)

64-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Assign an ARIA role to the badge <span> elements.

A generic <span> does not reliably support aria-label. Add role="img" to the active and inactive badge spans so screen readers can expose their accessible names.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/FacetChecklist.tsx` around lines 64 -
81, Add role="img" to both badge span elements rendered for active and inactive
facets in FacetChecklist, preserving their existing aria-label values and
styling.
next.config.js (1)

407-407: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

source matches only the exact path.

'/dev/payment-graph' does not match descendants. The shared predicate isPaymentNetworkExplorerPath in src/features/payment-network-explorer/privacy-route.ts treats ${PAYMENT_NETWORK_PATH}/... as private too. If the explorer gains a sub-route, these privacy headers would not apply to it. Adding a second entry for '/dev/payment-graph/:path*' keeps the header scope and the predicate scope aligned.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@next.config.js` at line 407, The headers configuration currently matches only
the exact payment graph path; add a companion source entry for the payment graph
descendants using the same header configuration as the existing
'/dev/payment-graph' entry. Keep it aligned with the descendant matching
performed by isPaymentNetworkExplorerPath and do not alter unrelated routes.
src/utils/csp-report.utils.ts (1)

73-80: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider matching the explorer URL in other report fields.

The filter inspects only document-uri. A CSP report can also carry the page URL in referrer. If a report for the explorer route arrives without document-uri, the current logic keeps it and the sensitive URL reaches the log. The route headers in next.config.js remove report delivery for this path, so this filter is defense in depth. Extending the same pathname check to referrer closes the remaining gap for one extra line.

🛡️ Proposed hardening
 export function shouldIgnoreCspReport(report: CspReport): boolean {
     if (isUnfixableOrigin(report['blocked-uri']) || isUnfixableOrigin(report['source-file'])) return true
-    const documentUri = report['document-uri']
-    if (typeof documentUri !== 'string') return false
-    try {
-        return isPaymentNetworkExplorerPath(new URL(documentUri, 'https://peanut.invalid').pathname)
-    } catch {
-        return false
-    }
+    return [report['document-uri'], report['referrer']].some((value) => {
+        if (typeof value !== 'string') return false
+        try {
+            return isPaymentNetworkExplorerPath(new URL(value, 'https://peanut.invalid').pathname)
+        } catch {
+            return false
+        }
+    })
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/csp-report.utils.ts` around lines 73 - 80, Extend the URL filtering
logic after the documentUri handling to also inspect the report’s referrer
field, safely validating it as a string and parsing it with the existing
fallback base URL. Return true when isPaymentNetworkExplorerPath matches the
referrer pathname, while preserving false for missing or invalid URL values and
reusing the existing error-handling pattern.
src/features/payment-network-explorer/NetworkCanvas.tsx (1)

41-41: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Name the dense-graph thresholds.

The literals 1000 at Line 79 and 4 / 1.8 at Line 109 control the same dense-view behavior as DENSE_LINK_LIMITS. Named constants next to DENSE_LINK_LIMITS would keep the tuning values in one place.

Also applies to: 79-79, 109-109

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/NetworkCanvas.tsx` at line 41, Define
named constants alongside DENSE_LINK_LIMITS for the dense-view tuning values
currently represented by 1000, 4, and 1.8, then replace those inline literals at
the referenced logic points with the new constants while preserving the existing
behavior.
src/features/payment-network-explorer/InfoTooltip.tsx (1)

40-52: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use useEffect for the tooltip position listeners.

This client component can be rendered during SSR, and useLayoutEffect in the open path can trigger React’s server rendering warning. The tooltip starts closed and stays hidden until position is set, so the listener setup does not need paint-blocking layout behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/payment-network-explorer/InfoTooltip.tsx` around lines 40 - 52,
Replace useLayoutEffect with useEffect in the tooltip listener setup around the
open state and updatePosition callback, preserving the existing position reset,
listener registration, and cleanup behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@next.config.js`:
- Around line 406-420: Update the global `/:path*` security-header configuration
so it excludes `/dev/payment-graph` and does not append its CSP reporting
headers or `Reporting-Endpoints` entry. Preserve the route-specific headers
using `contentSecurityPolicyReportOnly(false)` and the `csp-disabled` endpoint,
while leaving global behavior unchanged for all other paths.

In `@src/app/sw.ts`:
- Around line 79-84: Update the activate handler around
purgeSensitivePaymentNetworkCacheEntries so the promise passed to
event.waitUntil handles any rejection from cacheStorage.keys(), including a safe
catch or equivalent recovery path that prevents activation failure. Preserve the
existing per-cache purge behavior and ensure the purge failure is contained
without affecting unrelated caches.

In `@src/features/payment-network-explorer/__tests__/ExplorerSummary.test.tsx`:
- Around line 56-58: Update the number formatting in ExplorerSummary to pass an
explicit stable locale, preferably toLocaleString('en-US'), for the values
rendered in the tooltip. Ensure all formatted counts used by the
assertions—matched events, nodes, and relationships—use this locale while
preserving their existing output.

In `@src/features/payment-network-explorer/__tests__/headers.test.ts`:
- Line 37: Update the Reporting-Endpoints assertion in the headers test to match
the CSP report path without requiring a trailing quote, using the existing
null-safe fallback so an absent header still fails the containment check.

In `@src/features/payment-network-explorer/__tests__/privacy.test.ts`:
- Around line 48-49: Make the privacy test assertions verify concrete storage
and PostHog behavior rather than relying on object spreads or absent mock
properties. In the relevant test, inspect storage through explicit key/value or
length/key checks for the before/after state, and update the posthog-js
mock/assertion so the opt_out_capturing configuration is explicitly observable
and validated.

In `@src/features/payment-network-explorer/__tests__/sentryServerEdge.test.ts`:
- Around line 37-43: Update the NODE_ENV override in the test setup to preserve
writability, matching the existing headers.test.ts pattern, and wrap the
isolated module require in cleanup that always restores the original value even
when it throws. Keep the mock reset and module isolation behavior unchanged.

In `@src/features/payment-network-explorer/api.ts`:
- Around line 39-51: Update requestSignal to immediately abort its internal
controller when the provided external signal is already aborted, while
preserving the existing listener for future abort events and cleanup behavior.
Ensure callers such as usePaymentNetworkExplorer do not proceed with
fetchPaymentNetwork after an already-aborted signal.

In `@src/features/payment-network-explorer/ExplorerHeader.tsx`:
- Around line 29-41: Add role="group" to the view-toggle container div with
aria-label="Explorer view" so assistive technology announces the group name for
the aria-pressed buttons. Leave the existing button behavior and labeling
unchanged.

In `@src/features/payment-network-explorer/Inspector.tsx`:
- Around line 41-42: Extract the inline reveal form into a RevealForm child
component that owns the reason and revealError state, then render it keyed by
selection.node.id with the existing node, revealing, and onReveal inputs so both
states reset whenever the selected node changes.

In `@src/features/payment-network-explorer/PaymentNetworkExplorer.tsx`:
- Around line 32-35: Move consumeLegacyGraphUsername out of the useState
initializer in PaymentNetworkExplorer and invoke it from a mount-only effect
instead. Initialize legacyUsername and legacyFocusPending with SSR-safe empty
values, then update both states from the consumed username after mount so the
first server and client renders match while preserving legacy focus behavior.

In `@src/features/payment-network-explorer/RelationshipTable.tsx`:
- Around line 100-114: Replace aria-selected on the relationship row in the
table with aria-current so the selected state is exposed correctly while
preserving the static table semantics. Keep the existing selected styling, click
handling, and keyboard behavior unchanged.

In `@src/features/payment-network-explorer/SearchBox.tsx`:
- Around line 17-23: The submit handler in SearchBox’s submit function must
preserve username when onSearch results in an error. Clear the input only after
a successful search, or condition the existing setUsername('') on the error
state returned or updated by onSearch.

In `@src/features/payment-network-explorer/usePaymentNetworkExplorer.ts`:
- Around line 56-71: Update ensureSession so the deduplicated
createExplorerSession request is not created with a caller-scoped AbortSignal;
its shared lifetime must be independent of any individual effect cleanup. Add a
liveness check before setCurrentSession so an aborted or no-longer-active flow
cannot write the resolved session to state, while preserving request
deduplication and cleanup of sessionRequestRef.

---

Nitpick comments:
In `@next.config.js`:
- Line 407: The headers configuration currently matches only the exact payment
graph path; add a companion source entry for the payment graph descendants using
the same header configuration as the existing '/dev/payment-graph' entry. Keep
it aligned with the descendant matching performed by
isPaymentNetworkExplorerPath and do not alter unrelated routes.

In `@sentry.utils.ts`:
- Line 5: Move the /dev/payment-graph path into the shared route constants by
adding and exporting a PAYMENT_NETWORK_PATH symbol in routes.ts, then replace
hard-coded path values and local definitions in sentry.utils.ts,
privacy-route.ts, and other route code with that shared constant while
preserving existing route-matching behavior.

In `@src/app/api/csp-report/__tests__/route.test.ts`:
- Around line 26-61: Strengthen the CSP report route tests around the
parameterized fixtures by adding a non-explorer document URI case that expects
mockedFetch to be called, proving eligible reports are forwarded. Add coverage
for script-src-elem and script-src-attr in both supported report formats while
retaining the existing explorer-privacy assertions that expect no forwarding.

In `@src/app/payment-network-sw-privacy.ts`:
- Around line 1-11: The payment graph API path is duplicated in
isSensitivePaymentNetworkPathname; replace the local PAYMENT_GRAPH_API_PATH with
the shared explorer API-path constant used by payment-network-explorer callers,
updating imports or exports as needed. Preserve both exact and trailing-subpath
checks so privacy handling remains unchanged after route renames.

In `@src/app/sw.ts`:
- Around line 24-38: Move the PostHog `/relay/` explanation so it immediately
precedes the runtime-caching rule whose matcher handles `/relay/` requests,
keeping the payment-network rule’s comment directly attached to
`isSensitivePaymentNetworkUrl` and leaving rule behavior unchanged.

In
`@src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx`:
- Around line 169-171: Update the PaymentNetworkExplorer test setup to restore
all spies in an afterEach hook, including the console spies created in the test
and the Date.now spy. Remove the inline restoration from the test body, and
ensure beforeEach mock setup still runs after restoration for each test.
- Around line 197-244: Update the visibilitychange portion of the test case
“clears privileged reveals on background resume and pagehide” to set
document.visibilityState to 'hidden' before dispatching the synthetic
visibilitychange event, preserving the existing expiration and reveal
assertions.
- Around line 169-194: Register global cleanup outside test bodies so failures
cannot leak state: in
src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx#L169-L194,
move console.log, console.warn, console.error, and Date.now restoration into the
existing afterEach; in
src/features/payment-network-explorer/__tests__/headers.test.ts#L3-L21, restore
LOCAL_BUILD, NODE_ENV, and the console.log spy in afterEach; in
src/features/payment-network-explorer/__tests__/privacy.test.ts#L84-L94, move
document.head.appendChild restoration into afterEach; and in
src/features/payment-network-explorer/__tests__/sentryServerEdge.test.ts#L37-L43,
restore NODE_ENV in a finally block surrounding jest.isolateModules. Enable
restoreMocks in the Jest configuration to provide automatic spy restoration.

In `@src/features/payment-network-explorer/__tests__/privacy.test.ts`:
- Around line 84-94: Add an inline OpenGrep suppression for the dynamic
execution at `new Function` in the direct legacy URL test, documenting it as a
false positive for the trusted `googleAnalyticsBootstrapScript` output. Move spy
cleanup to the suite’s `afterEach` so `document.head.appendChild` is restored
even when assertions fail, and remove the test-local `append.mockRestore()` to
avoid duplicate cleanup.

In `@src/features/payment-network-explorer/__tests__/query.test.ts`:
- Around line 33-38: Add a test near the existing resolveExplorerWindow
maximum-window rejection assertion that passes a custom range exactly 120 days
before NOW through NOW and expects successful resolution. Keep the current
over-limit case unchanged, using the existing resolveExplorerWindow and NOW
symbols to cover the accepted boundary.

In `@src/features/payment-network-explorer/__tests__/reducedMotion.test.tsx`:
- Around line 28-55: Update mockMatchMedia and the reduced-motion test to
capture the change listener registered through addEventListener, then invoke it
with an updated matches value and assert useReducedMotion reflects the
preference change. Also exercise unmounting so the removeEventListener cleanup
in useReducedMotion is covered.

In `@src/features/payment-network-explorer/FacetChecklist.tsx`:
- Around line 64-81: Add role="img" to both badge span elements rendered for
active and inactive facets in FacetChecklist, preserving their existing
aria-label values and styling.

In `@src/features/payment-network-explorer/FilterPanel.tsx`:
- Around line 184-190: Update the Direction FacetChecklist onChange handler to
filter incoming strings against the known ExplorerFilters direction union before
calling onChange, instead of casting the entire array. Preserve only valid
direction values and pass that narrowed collection to onChange.

In `@src/features/payment-network-explorer/InfoTooltip.tsx`:
- Around line 40-52: Replace useLayoutEffect with useEffect in the tooltip
listener setup around the open state and updatePosition callback, preserving the
existing position reset, listener registration, and cleanup behavior.

In `@src/features/payment-network-explorer/Inspector.tsx`:
- Around line 171-172: In the Inspector component, memoize the result of
relationshipsForNode(relationships, selection.node.id) as nodeRelationships with
useMemo and appropriate dependencies. Render nodeRelationships.slice(0, 100) in
the connection list, and add a trailing UI note indicating the number of
additional connections when nodeRelationships.length exceeds 100.

In `@src/features/payment-network-explorer/NetworkCanvas.tsx`:
- Line 41: Define named constants alongside DENSE_LINK_LIMITS for the dense-view
tuning values currently represented by 1000, 4, and 1.8, then replace those
inline literals at the referenced logic points with the new constants while
preserving the existing behavior.

In `@src/features/payment-network-explorer/PaymentNetworkExplorer.tsx`:
- Around line 58-85: Replace the requestFilterKey JSON serialization and parsing
in the requestResult useMemo with direct references to the individual filter
fields, using those fields as the memo dependency set while preserving the
existing buildExplorerRequest and error-handling behavior. Keep the request
filters equivalent to the current ExplorerFilters object and remove the
unnecessary serialization round trip.

In `@src/features/payment-network-explorer/query.ts`:
- Around line 104-117: Update the states field in the returned filter object to
pass through sanitizeFilterValues while preserving isMovementState validation,
so states are filtered, deduplicated, and sorted consistently with the other
list filters. Keep the existing normalized state values and request-key behavior
for valid selections.

In `@src/features/payment-network-explorer/selectors.ts`:
- Around line 94-107: Update sortRelationships to reuse a single module-level
Intl.Collator for string comparisons instead of calling localeCompare directly
on each sort comparison. Keep numeric sorting and direction handling unchanged,
and use the shared collator in the non-numeric branch.

In `@src/features/payment-network-explorer/usePaymentNetworkExplorer.ts`:
- Line 182: Wrap the reload function in usePaymentNetworkExplorer with
useCallback so its reference remains stable across renders, using setReloadKey
as its dependency and preserving the existing increment behavior.

In `@src/utils/csp-report.utils.ts`:
- Around line 73-80: Extend the URL filtering logic after the documentUri
handling to also inspect the report’s referrer field, safely validating it as a
string and parsing it with the existing fallback base URL. Return true when
isPaymentNetworkExplorerPath matches the referrer pathname, while preserving
false for missing or invalid URL values and reusing the existing error-handling
pattern.

In `@tailwind.config.js`:
- Line 16: Update the Tailwind content configuration entry for the
payment-network-explorer feature to use the general src/features glob
'./src/features/**/*.{js,ts,jsx,tsx,mdx}', covering all current and future
feature directories while preserving the existing extensions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7c3290be-7d2e-4e9f-af81-152f058f77b4

📥 Commits

Reviewing files that changed from the base of the PR and between 608cf8f and 080d2f2.

📒 Files selected for processing (55)
  • instrumentation-client.ts
  • next.config.js
  • sentry.client.config.ts
  • sentry.edge.config.ts
  • sentry.server.config.ts
  • sentry.utils.ts
  • src/app/(mobile-ui)/dev/payment-graph/page.tsx
  • src/app/__tests__/payment-network-sw-privacy.test.ts
  • src/app/api/csp-report/__tests__/route.test.ts
  • src/app/layout.tsx
  • src/app/payment-network-sw-privacy.ts
  • src/app/sw.ts
  • src/constants/__tests__/routes.test.ts
  • src/constants/routes.ts
  • src/features/payment-network-explorer/DesktopGuard.tsx
  • src/features/payment-network-explorer/ExplorerHeader.tsx
  • src/features/payment-network-explorer/ExplorerStatePanel.tsx
  • src/features/payment-network-explorer/ExplorerSummary.tsx
  • src/features/payment-network-explorer/FacetChecklist.tsx
  • src/features/payment-network-explorer/FilterPanel.tsx
  • src/features/payment-network-explorer/FocusBanner.tsx
  • src/features/payment-network-explorer/InfoTooltip.tsx
  • src/features/payment-network-explorer/Inspector.tsx
  • src/features/payment-network-explorer/NetworkCanvas.tsx
  • src/features/payment-network-explorer/PaymentNetworkExplorer.tsx
  • src/features/payment-network-explorer/RelationshipDetails.tsx
  • src/features/payment-network-explorer/RelationshipTable.tsx
  • src/features/payment-network-explorer/SearchBox.tsx
  • src/features/payment-network-explorer/__tests__/ExplorerSummary.test.tsx
  • src/features/payment-network-explorer/__tests__/FacetChecklist.test.tsx
  • src/features/payment-network-explorer/__tests__/InfoTooltip.test.tsx
  • src/features/payment-network-explorer/__tests__/PaymentNetworkExplorer.test.tsx
  • src/features/payment-network-explorer/__tests__/api.test.ts
  • src/features/payment-network-explorer/__tests__/format.test.ts
  • src/features/payment-network-explorer/__tests__/headers.test.ts
  • src/features/payment-network-explorer/__tests__/privacy.test.ts
  • src/features/payment-network-explorer/__tests__/query.test.ts
  • src/features/payment-network-explorer/__tests__/reducedMotion.test.tsx
  • src/features/payment-network-explorer/__tests__/selectors.test.ts
  • src/features/payment-network-explorer/__tests__/sentryServerEdge.test.ts
  • src/features/payment-network-explorer/__tests__/usePaymentNetworkExplorer.test.tsx
  • src/features/payment-network-explorer/api.ts
  • src/features/payment-network-explorer/format.ts
  • src/features/payment-network-explorer/privacy-route.ts
  • src/features/payment-network-explorer/privacy.ts
  • src/features/payment-network-explorer/query.ts
  • src/features/payment-network-explorer/selectors.ts
  • src/features/payment-network-explorer/types.ts
  • src/features/payment-network-explorer/useDesktopViewport.ts
  • src/features/payment-network-explorer/useExplorerUrlState.ts
  • src/features/payment-network-explorer/usePaymentNetworkExplorer.ts
  • src/features/payment-network-explorer/useReducedMotion.ts
  • src/utils/__tests__/csp-report.utils.test.ts
  • src/utils/csp-report.utils.ts
  • tailwind.config.js

Comment thread next.config.js
Comment thread src/app/sw.ts
Comment thread src/features/payment-network-explorer/__tests__/headers.test.ts Outdated
Comment thread src/features/payment-network-explorer/__tests__/privacy.test.ts Outdated
Comment thread src/features/payment-network-explorer/Inspector.tsx Outdated
Comment thread src/features/payment-network-explorer/PaymentNetworkExplorer.tsx Outdated
Comment thread src/features/payment-network-explorer/RelationshipTable.tsx
Comment thread src/features/payment-network-explorer/SearchBox.tsx
Comment thread src/features/payment-network-explorer/usePaymentNetworkExplorer.ts
@0xkkonrad

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant