-
Notifications
You must be signed in to change notification settings - Fork 1
fix: cleanup disabled linting (web-345) #359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
… transfer details and graph components
WalkthroughRemoved many ESLint suppressions, deferred several state updates (setTimeout/RAF/microtask), moved some memoized logic to render-time or IIFEs, added provider-with-props support with Changes
Sequence Diagram(s)sequenceDiagram
participant UI as TransferDetailsDialog
participant MP as MultiProvider
participant ST as State
Note over UI: Effect runs when sender/recipient/originTxHash/multiProvider/origin/destination change
alt originTxHash present
UI->>MP: trySync explorer lookup
MP-->>UI: explorer info / error
UI->>ST: set originTxUrl (normalized) or noop on error
end
UI->>MP: getAddressUrl(sender)
MP-->>UI: senderUrl
UI->>ST: set senderUrl
UI->>MP: getAddressUrl(recipient)
MP-->>UI: recipientUrl
UI->>ST: set recipientUrl
sequenceDiagram
participant Page as PermissionGraphPage
participant Router as URL Params
participant GD as useGraphData
participant ST as State
Router-->>Page: id param present/absent
GD-->>Page: graphData available
alt id present
Page->>Page: find node by id
alt differs from selected
Page->>ST: setSelectedNode(node) [deferred via setTimeout]
Page->>ST: setIsSheetOpen(true) [deferred]
end
else id absent and node selected
Page->>ST: clear selection & close sheet [deferred]
end
sequenceDiagram
participant PR as ProviderRenderer
participant App as AppContextProvider
participant P as ProviderItem (component or {component,props})
App->>PR: pass providers array (includes createProviderWithProps item)
PR->>PR: fold providers right-to-left
alt provider has props
PR->>P: render component with bound props and accumulated children
else
PR->>P: render component directly with children
end
PR-->>App: composed provider tree
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro Disabled knowledge base sources:
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ 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). (9)
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. Comment |
🚀 torus-cache Preview deployment will be available at: https://pr-359.torus-cache.torus.network |
🚀 torus-allocator Preview deployment will be available at: https://pr-359.torus-allocator.torus.network |
🚀 torus-page Preview deployment will be available at: https://pr-359.torus-page.torus.network |
🚀 torus-wallet Preview deployment will be available at: https://pr-359.torus-wallet.torus.network |
🚀 torus-portal Preview deployment will be available at: https://pr-359.torus-portal.torus.network |
🚀 torus-governance Preview deployment will be available at: https://pr-359.torus-governance.torus.network |
🚀 torus-bridge Preview deployment will be available at: https://pr-359.torus-bridge.torus.network |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
…mo hooks across various components
# Conflicts: # apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx # apps/torus-portal/src/app/(pages)/(permission-graph)/_components/permission-graph-command.tsx
… transfer details and wallet provider components
…ecessary comment in use-weekly-usd hook
…pdates in various components
…nd enhancing state management in various components
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (11)
apps/torus-wallet/src/app/_components/transactions-sheet.tsx (1)
44-44
: Tailwind arbitrary width typo: w-400px] → w-[400px].The current class is invalid and drops the width style.
Apply this diff:
- <SheetContent className="w-400px] z-[70] flex h-full flex-col gap-4"> + <SheetContent className="w-[400px] z-[70] flex h-full flex-col gap-4">apps/torus-bridge/src/app/_components/transfer-token/_components/transfer-token-form.tsx (1)
44-66
: Form resets risk: non-memoizedinitialValues
+enableReinitialize
can wipe user input on any re-render.With a new object each render, Formik may reinitialize repeatedly, and your
useEffect
depending oninitialValues.*
can loop navigation updates.Re-memoize
initialValues
by inputs:-import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; @@ - const initialValues = (() => { + const initialValues = useMemo(() => { if (fromParam && toParam) { return { origin: fromParam, destination: toParam, tokenIndex: getIndexForTokenByChainName(warpCore, fromParam), amount: "", recipient: "", }; } const firstToken = warpCore.tokens[0]; const connectedToken = firstToken?.connections?.[0]; return { origin: firstToken?.chainName ?? "", destination: connectedToken?.token.chainName ?? "", tokenIndex: getIndexForToken(warpCore, firstToken), amount: "", recipient: "", }; - })(); + }, [warpCore, fromParam, toParam]);Please verify that typing into fields no longer resets on unrelated state updates (e.g., accounts or tokens refresh).
apps/torus-wallet/src/hooks/useAPR.ts (2)
129-142
: Stale flags: useMemo with [queries] won’t update when inner fields change.
isAnyLoading
,isAnyError
, andisDataComplete
won’t recompute as query fields mutate without array identity change. Compute directly (no memo) or depend on individual fields.- const isAnyLoading = useMemo( - () => queries.some((query) => query.isPending), - [queries], - ); - - const isAnyError = useMemo( - () => queries.some((query) => query.isError), - [queries], - ); - - const isDataComplete = useMemo( - () => queries.every((query) => !!query.data), - [queries], - ); + const isAnyLoading = + totalStakeQuery.isPending || + totalIssuanceQuery.isPending || + recyclingPercentageQuery.isPending || + treasuryEmissionFeeQuery.isPending || + incentivesRatioQuery.isPending; + + const isAnyError = + totalStakeQuery.isError || + totalIssuanceQuery.isError || + recyclingPercentageQuery.isError || + treasuryEmissionFeeQuery.isError || + incentivesRatioQuery.isError; + + const isDataComplete = + !!totalStakeQuery.data && + !!totalIssuanceQuery.data && + !!recyclingPercentageQuery.data && + !!treasuryEmissionFeeQuery.data && + !!incentivesRatioQuery.data;
78-99
: Big precision loss converting 1e18-scaled floats via Number → BigInt.
Math.round(x * 1e18)
exceeds JS safe-integer range; the rounding is imprecise beforeBigInt(...)
. Use a smaller precise scale (e.g., 1e6) or a string-based scaler.- const PRECISION = 10n ** 18n; // 10^18 for high precision + // Use a safe, precise scale for Number -> BigInt conversions. + const PRECISION = 1_000_000n; // 1e6 is within JS number safe integer when rounding // Convert ratios to bigint with precision - const incentivesRatioScaled = BigInt( - Math.round(incentivesRatio * Number(PRECISION)), - ); - const treasuryFeeScaled = BigInt(Math.round(treasuryFee * Number(PRECISION))); + const incentivesRatioScaled = BigInt(Math.round(incentivesRatio * Number(PRECISION))); + const treasuryFeeScaled = BigInt(Math.round(treasuryFee * Number(PRECISION)));If higher precision is required, switch to a string scaler (no float math) and parse to BigInt; I can provide that helper.
apps/torus-governance/src/app/(expanded-pages)/agent-application/[id]/_components/agent-application-expanded-vote-bars.tsx (1)
50-57
: Guard division by zero and clamp widths to [0, 100].When there are 0 cadre members,
againstWidth
becomesInfinity
. Also, widths can exceed 100% after reaching thresholds.const totalCadreMembers = cadreListData.length; - const threshold = Math.floor(totalCadreMembers / 2) + 1; + const threshold = Math.floor(totalCadreMembers / 2) + 1; // Calculate widths based on the total possible votes (cadre members) - const favorableWidth = (favorableVotes / threshold) * 100; - const againstWidth = (againstVotes / totalCadreMembers) * 100; + const favorableWidthRaw = threshold > 0 ? (favorableVotes / threshold) * 100 : 0; + const againstWidthRaw = + totalCadreMembers > 0 ? (againstVotes / totalCadreMembers) * 100 : 0; + const favorableWidth = Math.max(0, Math.min(100, favorableWidthRaw)); + const againstWidth = Math.max(0, Math.min(100, againstWidthRaw));apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx (2)
118-132
: Fix:connectedNode
lookup may fail whensource/target
are objects.
permission.source/target
can be objects; comparingn.id
against the object will never match. ComputesourceId/targetId
first and use them in the lookup.- const isOutgoing = permission.type === "outgoing"; - const connectedNode = graphData?.nodes.find( - (n) => n.id === (isOutgoing ? permission.target : permission.source), - ); - const connectedAddress = - connectedNode?.fullAddress ?? connectedNode?.id ?? ""; - - const sourceId = - typeof permission.source === "object" - ? permission.source.id - : permission.source; - const targetId = - typeof permission.target === "object" - ? permission.target.id - : permission.target; + const isOutgoing = permission.type === "outgoing"; + const sourceId = + typeof permission.source === "object" && permission.source + ? permission.source.id + : permission.source; + const targetId = + typeof permission.target === "object" && permission.target + ? permission.target.id + : permission.target; + const connectedNode = graphData?.nodes.find( + (n) => n.id === (isOutgoing ? targetId : sourceId), + ); + const connectedAddress = + connectedNode?.fullAddress ?? connectedNode?.id ?? "";
1-10
: Add "use client"; as the first line of the fileapps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx is missing the directive and uses client-only hooks (useRouter/usePathname). Add
"use client";
as the top-most line.apps/torus-wallet/src/hooks/useTransactions.tsx (4)
38-45
: Do not call setState during render; move resets into an effect keyed by resetKey.Calling multiple setters in render is a render-phase update that can cause warnings, re-render loops, and inconsistent effect ordering. It also fails to trigger a refetch when lastTransactionTimestamp changes while page is already 1 (page doesn’t change, so the load effect won’t rerun).
Apply this diff to fix and ensure a refetch occurs on resetKey changes:
- if (currentResetKey !== resetKey) { - setCurrentResetKey(resetKey); - setPage(1); - setTransactions([]); - setTotalTransactions(0); - setHasMore(false); - setIsLoading(false); - } + useEffect(() => { + setCurrentResetKey(resetKey); + setPage(1); + setTransactions([]); + setTotalTransactions(0); + setHasMore(false); + setIsLoading(false); + }, [resetKey]);Also update the data-loading effect deps to observe resets:
- }, [address, page, filters, itemsPerPage, getTransactionsByWallet]); + }, [address, page, filters, itemsPerPage, getTransactionsByWallet, resetKey, currentResetKey]);
56-87
: Replace setTimeout(..., 0) with queueMicrotask for page 1; keep timeout for subsequent pages.This aligns with the PR’s lint cleanup and avoids zero-timeout macrotasks while preserving the 100ms UX delay on later pages. Maintain cancel-ability by using an abort flag for the microtask path.
- // Small delay to prevent rapid calls and improve UX - const delay = page === 1 ? 0 : 100; - - const timeoutId = setTimeout(() => { - const options: TransactionQueryOptions = { - page, - limit: itemsPerPage, - type: filters.type, - fromAddress: filters.fromAddress, - toAddress: filters.toAddress, - hash: filters.hash, - startDate: filters.startDate, - endDate: filters.endDate, - orderBy: filters.orderBy, - }; - - if (!address) return; - - const result = getTransactionsByWallet(address, options); - - // For page 1, replace all transactions. For other pages, append - setTransactions((prev) => - page === 1 ? result.transactions : [...prev, ...result.transactions], - ); - setTotalTransactions(result.total); - setHasMore(result.hasMore); - setIsLoading(false); - }, delay); - - // Return cleanup function to prevent memory leaks - return () => clearTimeout(timeoutId); + // Small delay to prevent rapid calls on subsequent pages. + // For page 1, defer via microtask to avoid zero-timeout. + const schedule = (fn: () => void) => { + if (page === 1) { + let aborted = false; + queueMicrotask(() => { + if (aborted) return; + fn(); + }); + return () => { + aborted = true; + }; + } + const id = setTimeout(fn, 100); + return () => clearTimeout(id); + }; + + const cleanup = schedule(() => { + const options: TransactionQueryOptions = { + page, + limit: itemsPerPage, + type: filters.type, + fromAddress: filters.fromAddress, + toAddress: filters.toAddress, + hash: filters.hash, + startDate: filters.startDate, + endDate: filters.endDate, + orderBy: filters.orderBy, + }; + + if (!address) return; + + const result = getTransactionsByWallet(address, options); + + // For page 1, replace all transactions. For other pages, append + setTransactions((prev) => + page === 1 ? result.transactions : [...prev, ...result.transactions], + ); + setTotalTransactions(result.total); + setHasMore(result.hasMore); + setIsLoading(false); + }); + + return cleanup;
47-51
: Guard the loader until the reset state is applied — add a guard and ensure deps update.
- Add early-return at the top of the loader useEffect: if (currentResetKey !== resetKey) return;
- Include currentResetKey (or resetKey) in the effect dependency array so the loader re-runs only after the reset state is applied.
- Move the render-time reset (currently calling setCurrentResetKey / setPage / setTransactions etc.) out of the render body into a dedicated useEffect that runs on resetKey to avoid setState during render.
File: apps/torus-wallet/src/hooks/useTransactions.tsx — reset block (lines ~38–45) and loader useEffect (starts ~line 47).
47-91
: Remaining zero-delay setTimeout(...) usages found — address or justifyScan uncovered explicit zero-delay timeouts at:
- apps/torus-portal/src/app/(pages)/(permission-graph)/page.tsx:65
- apps/torus-portal/src/app/(pages)/network-operations/manage-agent/_components/update-agent-form.tsx:76, 138
- apps/torus-portal/src/app/(pages)/permissions/create-permission/capability/_components/create-capability-flow/create-capability-flow-hooks/use-permission-select-handler.ts:397
- apps/torus-governance/src/app/_components/expanded-view-content.tsx:32
- apps/torus-governance/src/app/_components/shape-network-modal.tsx:86
- apps/torus-wallet/src/app/(transfers)/_components/faucet/faucet-form.tsx:46
- packages/ui/src/components/wallet-connection-warning.tsx:22
Note: apps/torus-wallet/src/hooks/useTransactions.tsx still uses a conditional delay (page === 1 ? 0 : 100) which results in a zero-delay on page 1 — decide whether that is acceptable.
Action: remove/replace zero-delay setTimeouts or add a brief justification/comments where retaining 0 is intentional; update PR accordingly.
🧹 Nitpick comments (50)
apps/torus-page/src/app/_components/hover-header/index.tsx (6)
25-30
: Use Math.hypot for readability and potential perf gains.
Simpler and avoids duplicate pow calls.- return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); + return Math.hypot(x2 - x1, y2 - y1);
32-57
: Throttle mousemove state updates with rAF.
Reduces re-render pressure on hot path and prevents flooding setState.- (event: MouseEvent) => { + (event: globalThis.MouseEvent) => { @@ - setGlowSize(scale / 1.2); + if (rafRef.current !== null) cancelAnimationFrame(rafRef.current); + rafRef.current = requestAnimationFrame(() => setGlowSize(scale / 1.2));Add once near other refs:
// above handlers const rafRef = useRef<number | null>(null);
59-66
: Attach mousemove only when needed and cancel pending rAF on cleanup.
Avoids global listener when header isn’t interacted with; ensures rAF is cleared.-useEffect(() => { - window.addEventListener("mousemove", handleMouseMove); - - return () => { - window.removeEventListener("mousemove", handleMouseMove); - }; -}, [handleMouseMove]); +useEffect(() => { + if (!isHovered && !isVisible) return; + window.addEventListener("mousemove", handleMouseMove); + return () => { + window.removeEventListener("mousemove", handleMouseMove); + if (rafRef.current !== null) { + cancelAnimationFrame(rafRef.current); + rafRef.current = null; + } + }; +}, [handleMouseMove, isHovered, isVisible]);
67-79
: Hoist static variants to a module-level constant.
This object is static; removing useMemo simplifies and slightly reduces hook work.Example:
// outside component const GLOW_VARIANTS: Variants = { pulse: (scale: number) => ({ scale: [scale, scale * 1.2, scale], transition: { duration: 2, repeat: Infinity, ease: "easeInOut" }, }), }; // usage: variants={GLOW_VARIANTS}
81-88
: Use PointerEvent for broader input coverage.
Covers mouse, touch, pen uniformly.- const handleClickOutside = useCallback((event: MouseEvent) => { + const handleClickOutside = useCallback((event: globalThis.PointerEvent) => {
90-99
: Listen for pointerdown instead of mousedown.
Ensures outside-close works on touch devices too.- if (isVisible) { - document.addEventListener("mousedown", handleClickOutside); - } + if (isVisible) { + document.addEventListener("pointerdown", handleClickOutside); + } @@ - document.removeEventListener("mousedown", handleClickOutside); + document.removeEventListener("pointerdown", handleClickOutside);apps/torus-wallet/src/app/_components/transactions-sheet.tsx (2)
26-29
: rAF deferral is fine; avoid background-tab throttling keeping heavy content mounted.requestAnimationFrame is throttled in background tabs; closing the sheet and then backgrounding the tab can leave Transactions mounted longer than necessary. Two low-risk options:
- Prefer queueMicrotask for the closing path (runs regardless of frame cadence):
- const frameId = requestAnimationFrame(() => - setShouldRenderContent(false), - ); - return () => cancelAnimationFrame(frameId); + let canceled = false; + queueMicrotask(() => { + if (!canceled) setShouldRenderContent(false); + }); + return () => { + canceled = true; + };
- Or additionally gate render by isOpen so content unmounts immediately when closed (even if rAF is throttled):
// around lines 53-60 {isOpen && shouldRenderContent && selectedAccount && ( <Transactions selectedAccount={selectedAccount} /> )} {isOpen && shouldRenderContent && !selectedAccount && ( <div className="text-muted-foreground flex flex-1 items-center justify-center"> No account selected </div> )}
23-24
: Extract magic number 150ms into a named constant.Improves readability and discoverability of the UX timing.
Example:
const OPEN_CONTENT_DELAY_MS = 150; // ... const timer = setTimeout(() => setShouldRenderContent(true), OPEN_CONTENT_DELAY_MS);.gitignore (2)
47-48
: Broadened ignore patterns likely unintended — use exact-name matches instead of suffix globs.
*PLANS.md
and*TASKS.md
will ignore any file ending with those names (e.g.,team-PLANS.md
,OKR_TASKS.md
). If you meant “files named exactly PLANS.md/TASKS.md anywhere,” drop the leading*
. If you meant only repo-root files, anchor with/
.Apply one of the following:
Exact-name anywhere:
-*PLANS.md -*TASKS.md +PLANS.md +TASKS.mdRoot-only:
-*PLANS.md -*TASKS.md +/PLANS.md +/TASKS.md
23-23
: Deduplicate identical ignore entry.
**/.claude/settings.local.json
appears twice; keep a single instance.-**/.claude/settings.local.json
Also applies to: 46-46
apps/torus-bridge/src/app/_components/buttons/connect-aware-submit-button.tsx (1)
46-50
: Tighten callback deps look good; drop unnecessaryvoid
.Reducing deps to
[setErrors, setTouched]
avoids stale closures and redundant timers. Thevoid
beforesetTouched({})
isn’t needed (Formik’s setter returns void).const clearErrors = useCallback(() => { setErrors({}); - void setTouched({}); + setTouched({}); }, [setErrors, setTouched]);apps/torus-bridge/src/hooks/use-balance-watcher.ts (1)
21-37
: Deps change is correct; consider trimming duplicate checks in condition.Switching deps to
[balance, recipient, toast]
is appropriate; refs shouldn’t be in the array. The predicate repeats recipient equality checks; you can simplify without changing behavior.- if ( - recipient && - balance && - prev.recipient === recipient && - prevRecipientBalance.current.balance && - prevRecipientBalance.current.recipient === recipient && - balance.token.equals(prevRecipientBalance.current.balance.token) && - balance.amount > prevRecipientBalance.current.balance.amount - ) { + if ( + recipient && + balance && + prev.recipient === recipient && + prevRecipientBalance.current.balance && + balance.token.equals(prevRecipientBalance.current.balance.token) && + balance.amount > prevRecipientBalance.current.balance.amount + ) {apps/torus-bridge/src/app/_components/tokens/token-list-modal.tsx (2)
100-129
: Recompute on every render could be costly; memoize if the list gets large.If
warpCore.tokens
is sizable, this map/sort/filter each render can cause UI jank. Optional: memoize by inputs.-import { useEffect, useRef, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; @@ - const tokens = (() => { + const tokens = useMemo(() => { const q = searchQuery.trim().toLowerCase(); const multiChainTokens = warpCore.tokens.filter((t) => t.isMultiChainToken(), ); const tokensWithRoute = warpCore.getTokensForRoute(origin, destination); return ( multiChainTokens .map((t) => ({ token: t, disabled: !tokensWithRoute.includes(t), })) .sort((a, b) => { if (a.disabled && !b.disabled) return 1; else if (!a.disabled && b.disabled) return -1; else return 0; }) // Filter down to search query .filter((t) => { if (!q) return t; return ( t.token.name.toLowerCase().includes(q) || t.token.symbol.toLowerCase().includes(q) || t.token.addressOrDenom.toLowerCase().includes(q) ); }) // Hide/show disabled tokens .filter((t) => (config.showDisabledTokens ? true : !t.disabled)) ); - })(); + }, [warpCore, origin, destination, searchQuery, config.showDisabledTokens]);
134-141
: Avoid index keys to reduce re-mount churn.Use a stable key (chainName + addressOrDenom) to prevent unnecessary re-mounts when the list changes.
- tokens.map((t, i) => ( + tokens.map((t) => ( <button @@ - key={i} + key={`${t.token.chainName}:${t.token.addressOrDenom}`}apps/torus-governance/src/app/_components/shape-network-modal.tsx (1)
85-91
: PreferqueueMicrotask
oversetTimeout(0)
for next-tick deferral.This PR’s rationale favors microtasks for zero-delay defers. Switching improves consistency and avoids timer clamping.
- if (shouldBeOpen) { - const timer = setTimeout(() => { - setIsOpen(true); - sessionStorage.removeItem("shapeNetworkModalOpen"); - }, 0); - return () => clearTimeout(timer); - } + if (shouldBeOpen) { + queueMicrotask(() => { + setIsOpen(true); + sessionStorage.removeItem("shapeNetworkModalOpen"); + }); + }apps/torus-wallet/src/app/(transfers)/_components/faucet/faucet-form.tsx (1)
44-50
: UserequestAnimationFrame
(or keep synchronoususeLayoutEffect
) instead ofsetTimeout(0)
for measurement.Deferring to a macrotask can cause a visible flicker: first render with width 0, then update. Use rAF and cancel on cleanup.
- useLayoutEffect(() => { - if (containerRef.current) { - const timer = setTimeout(() => { - setWidth(containerRef.current?.offsetWidth ?? 0); - }, 0); - return () => clearTimeout(timer); - } - }, []); + useLayoutEffect(() => { + if (!containerRef.current) return; + const id = requestAnimationFrame(() => { + setWidth(containerRef.current?.offsetWidth ?? 0); + }); + return () => cancelAnimationFrame(id); + }, []);Optional follow-up: consider a ResizeObserver to keep the menu width in sync on container resizes.
apps/torus-governance/hooks/use-sign-in.tsx (3)
24-33
: Deferring with microtask: add unmount guardqueueMicrotask can still fire after unmount. Add a canceled flag so setState is skipped.
useEffect(() => { if (!(viewMode === "dao-portal")) return; const auth = localStorage.getItem("authorization"); - if (!auth) { - queueMicrotask(() => setIsUserAuthenticated(false)); - return; - } + if (!auth) { + let canceled = false; + queueMicrotask(() => { + if (!canceled) setIsUserAuthenticated(false); + }); + return () => { + canceled = true; + }; + }
61-63
: Deps array change is safe but unnecessarysetIsUserAuthenticated is stable; including it is harmless but not required. Feel free to drop it to reduce churn.
64-71
: Also guard the second microtask against unmountSame rationale as above.
useEffect(() => { const favoriteWalletAddress = localStorage.getItem("favoriteWalletAddress"); if (!selectedAccount || favoriteWalletAddress === selectedAccount.address) return; - queueMicrotask(() => setIsUserAuthenticated(null)); + let canceled = false; + queueMicrotask(() => { + if (!canceled) setIsUserAuthenticated(null); + }); + return () => { + canceled = true; + };apps/torus-portal/src/app/(pages)/(permission-graph)/_components/force-graph/use-graph-data.ts (2)
26-27
: Naming nit: clarify intentConsider naming to whitelistedAgents for readability.
- const allAgents = allAgentsData?.filter((agent) => agent.isWhitelisted) ?? []; + const whitelistedAgents = + allAgentsData?.filter((agent) => agent.isWhitelisted) ?? [];
34-51
: Pass a safe default for signalsIf createSimplifiedGraphData tolerates empty arrays, prefer a default to avoid internal undefined checks.
- return createSimplifiedGraphData( - allAgents, + return createSimplifiedGraphData( + whitelistedAgents, allPermissions, allocatorAddress, - allSignals, + allSignals ?? [], allAgentsData, );apps/torus-governance/src/app/_components/expanded-view-content.tsx (1)
27-36
: Use rAF + layout effect instead of setTimeout(0) for visual measurementFor UI-driven measurements/updates, requestAnimationFrame in useLayoutEffect avoids a macrotask delay and flicker, and it’s cancelable.
- useEffect(() => { + useLayoutEffect(() => { // Check if the content is overflowing to decide whether to show the expand/collapse button if (contentRef.current) { const contentHeight = contentRef.current.scrollHeight; const maxAllowedHeight = 250; - const timer = setTimeout(() => { - setIsOverflowing(contentHeight > maxAllowedHeight); - }, 0); - return () => clearTimeout(timer); + const raf = requestAnimationFrame(() => { + setIsOverflowing(contentHeight > maxAllowedHeight); + }); + return () => cancelAnimationFrame(raf); } }, [body]);Additional change required outside this hunk:
- import { useEffect, useRef, useState } from "react"; + import { useLayoutEffect, useRef, useState } from "react";apps/torus-portal/src/app/(pages)/network-operations/manage-agent/_components/update-agent-form.tsx (2)
72-80
: Replace setTimeout(0) with rAF for preview updatesPreview image swap is visual; rAF aligns with paint and gives a proper cancel path.
- const timer = setTimeout(() => { - setCurrentImagePreview(currentImageBlobUrl); - }, 0); - return () => clearTimeout(timer); + const raf = requestAnimationFrame(() => { + setCurrentImagePreview(currentImageBlobUrl); + }); + return () => cancelAnimationFrame(raf);
121-145
: Avoid macrotask and add cleanup for form resetUse a microtask with an unmount guard; fewer delays and no timer handle to manage.
useEffect(() => { if (agent && agentMetadata) { const originalData = { name: agent.name ?? "", shortDescription: agentMetadata.metadata.short_description || "", description: agentMetadata.metadata.description || "", website: agentMetadata.metadata.website ?? "", apiUrl: agent.apiUrl ?? "", imageFile: undefined, socials: { twitter: agentMetadata.metadata.socials?.twitter ?? "", github: agentMetadata.metadata.socials?.github ?? "", telegram: agentMetadata.metadata.socials?.telegram ?? "", discord: agentMetadata.metadata.socials?.discord ?? "", }, }; - - setTimeout(() => { - setOriginalFormData(originalData); - form.reset(originalData); - setHasUnsavedChanges(false); - }, 0); + let canceled = false; + queueMicrotask(() => { + if (canceled) return; + setOriginalFormData(originalData); + form.reset(originalData); + setHasUnsavedChanges(false); + }); + return () => { + canceled = true; + }; } }, [agent, agentMetadata, form]);apps/torus-governance/hooks/use-agent-applications.tsx (1)
53-127
: Tighten the null filter with a type guardAvoid the Boolean cast trick; a local predicate is clearer and preserves types.
- .filter( - Boolean as unknown as ( - value: ApplicationResult | null, - ) => value is ApplicationResult, - ) + .filter( + (v): v is ApplicationResult => v !== null + )apps/torus-portal/src/hooks/use-weekly-usd.ts (3)
27-29
: Fix typos in comment."dolar Brice (<- lol)" → "dollar price" and "Coingecko" → "CoinGecko".
- // Queries the Torus dolar Brice (<- lol) from Coingecko + // Queries the Torus dollar price from CoinGecko
86-90
: Optional: avoid precision loss when amounts can grow.
tokensPerWeek.toNumber()
can lose precision for large values. Consider using a decimal-safe helper (e.g., returning a JS number only after bounding) or computingusdValue
from a string/Big representation if available.
92-100
: Hoist number formatters to avoid re-allocating each render.Create reusable
Intl.NumberFormat
instances at module scope (stateless), keeping with the PR’s removal of memoization.+const TORUS_FORMAT = new Intl.NumberFormat("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); +const USD_FORMAT = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", minimumFractionDigits: 2, maximumFractionDigits: 2 }); const displayTokensPerWeek = (() => { if (isLoading || isError) return "0.00 TORUS"; - return ( - tokensPerWeek.toNumber().toLocaleString("en-US", { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }) + " TORUS" - ); + return TORUS_FORMAT.format(tokensPerWeek.toNumber()) + " TORUS"; })(); const displayUsdValue = (() => { if (isLoading || isError) return "$0.00"; - return usdValue.toLocaleString("en-US", { - style: "currency", - currency: "USD", - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }); + return USD_FORMAT.format(usdValue); })();Also applies to: 103-111
apps/torus-governance/src/app/_components/filter-content.tsx (2)
62-81
: Tighten pathname checks to avoid false positives.Using
includes("/proposals")
andincludes("/agents")
may match unintended routes (e.g.,/proposals-archive
). Prefer segment-aware checks.- if (pathname.includes("/proposals")) { + if (pathname === "/proposals" || pathname.startsWith("/proposals/")) { ... - } else if (pathname.includes("/agents")) { + } else if (pathname === "/agents" || pathname.startsWith("/agents/")) { ...
120-123
: Optional: avoid history spam on every keystroke.
router.push
on each input change can bloat history. Considerrouter.replace
or a small debounce.- router.push(`?${query}`); + router.replace(`?${query}`);apps/torus-wallet/src/hooks/useAPR.ts (1)
112-127
: Optional: dropqueries
useMemo entirely.Since derived flags are now direct,
queries
can be a plain array or removed.- const queries = useMemo( - () => [ - totalStakeQuery, - totalIssuanceQuery, - recyclingPercentageQuery, - treasuryEmissionFeeQuery, - incentivesRatioQuery, - ], - [ - totalStakeQuery, - totalIssuanceQuery, - recyclingPercentageQuery, - treasuryEmissionFeeQuery, - incentivesRatioQuery, - ], - ); + const queries = [ + totalStakeQuery, + totalIssuanceQuery, + recyclingPercentageQuery, + treasuryEmissionFeeQuery, + incentivesRatioQuery, + ];apps/torus-page/src/app/_components/torus-animation.tsx (1)
72-91
: Dispose ShaderMaterial on unmount to free GPU memory.Add a cleanup to call
dispose()
for safety, especially when using<primitive object={...} attach="material" />
.const shaderMaterial = useMemo(() => { const uniforms = { time: { value: 0 }, intensity: { value: 0.8 }, speed: { value: 0.1 }, lineThickness: { value: 0.01 }, pixelSize: { value: 8 }, }; return new THREE.ShaderMaterial({ uniforms, vertexShader, fragmentShader, transparent: true, depthWrite: false, depthTest: true, side: THREE.DoubleSide, blending: THREE.AdditiveBlending, }); }, []); + + // Ensure material gets disposed on unmount + useEffect(() => { + return () => { + shaderMaterial.dispose(); + }; + }, [shaderMaterial]);apps/torus-portal/src/app/(pages)/(permission-graph)/_components/force-graph/use-graph-interactions.ts (1)
12-17
: Simplified handler is fine here.Given the small body, dropping
useCallback
is acceptable. If passed deep, consider memoizing later for render churn.apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx (1)
78-89
: Avoid shadowing state variableoriginTxUrl
.Local tuple element
originTxUrl
shadows the state variable of the same name, which hurts readability and increases risk of mistakes. Rename the local binding.- const [txUrlError, originTxUrl] = trySync(() => + const [txUrlError, txUrl] = trySync(() => multiProvider.tryGetExplorerTxUrl(origin, { hash: originTxHash }), ); @@ - } else if (originTxUrl) { - setOriginTxUrl(fixDoubleSlash(originTxUrl)); + } else if (txUrl) { + setOriginTxUrl(fixDoubleSlash(txUrl)); }apps/torus-bridge/src/app/_components/transfer-details/index.tsx (1)
17-29
: Auto-close the modal when there’s no latest transfer.Currently the modal never auto-closes if transfers become empty or loading resumes. Add a symmetric close path.
useLayoutEffect(() => { const shouldShowModal = !transferLoading && transfers.length > 0; const latestTransfer = shouldShowModal ? transfers[transfers.length - 1] : null; if (latestTransfer && latestTransfer !== selectedTransfer) { queueMicrotask(() => { setSelectedTransfer(latestTransfer); setIsModalOpen(true); }); + } else if (!shouldShowModal && (isModalOpen || selectedTransfer)) { + queueMicrotask(() => { + setIsModalOpen(false); + setSelectedTransfer(null); + }); } - }, [transfers, transferLoading, selectedTransfer]); + }, [transfers, transferLoading, selectedTransfer, isModalOpen]);Also applies to: 29-29
apps/torus-bridge/src/app/_components/tokens/token-select-field.tsx (2)
27-31
: SimplifyisAutomaticSelection
expression.Equivalent and clearer as “length <= 1”.
- const isAutomaticSelection = - tokensWithRoute.length !== 1 ? tokensWithRoute.length === 0 : true; + const isAutomaticSelection = tokensWithRoute.length <= 1;
27-31
: StabilizetokensWithRoute
identity to reduce effect churn.Memoize to avoid re-running the effect on every render when the route hasn’t changed.
Add import:
import { useMemo } from "react";Memoize:
const tokensWithRoute = useMemo( () => warpCore.getTokensForRoute(origin, destination), [warpCore, origin, destination], );apps/torus-governance/src/app/_components/comments/view-comment.tsx (2)
151-166
: Avoid re-sorting on every render; consider memoizing or precomputing keys.Sorting and repeatedly constructing Date objects each render can add up with many comments. Using useMemo (keyed by comments reference and sortBy) keeps behavior while avoiding unnecessary work.
Apply:
- const sortedComments = (() => { + const sortedComments = useMemo(() => { if (!comments) return []; return [...comments].sort((a, b) => { if (sortBy === "newest") { return ( new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ); } else if (sortBy === "oldest") { return ( new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime() ); } else { return (Number(b.likes) || 0) - (Number(a.likes) || 0); } }); - })(); + }, [comments, sortBy]);And add the import:
-import { useCallback, useEffect, useLayoutEffect, useState } from "react"; +import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from "react";
188-240
: Nice consolidation of vote logic; add in-flight guard to prevent double submits.Wire the mutations’ pending state to disable buttons and avoid duplicate requests; optional optimistic UI can further improve UX.
If you’re on React Query v5,
isPending
is available; otherwise useisLoading
.const castVoteMutation = api.commentInteraction.reaction.useMutation(); const deleteVoteMutation = api.commentInteraction.deleteReaction.useMutation(); + const isVoting = + (castVoteMutation as any).isPending ?? castVoteMutation.isLoading || + (deleteVoteMutation as any).isPending ?? deleteVoteMutation.isLoading || false;Outside this block, enable the disabled props:
- // disabled={isVoting || !selectedAccount?.address} + disabled={isVoting || !selectedAccount?.address}apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-signals-accordion.tsx (1)
23-27
: Recompute cost is tiny here, but memoizing is a safe default if the list grows.Filtering on each render is fine now; using useMemo guards against future growth or accidental re-renders.
- const nodeSignals = (() => { + const nodeSignals = useMemo(() => { if (!allSignals || !selectedNode?.id) return []; return allSignals.filter((signal) => signal.agentKey === selectedNode.id); - })(); + }, [allSignals, selectedNode?.id]);Also add:
+import { useMemo } from "react";
apps/torus-portal/src/app/(pages)/(permission-graph)/_components/permission-graph-command.tsx (1)
93-178
: Build search groups once per dependency change to avoid heavy per-render work.This block walks several large collections; recomputation on keystroke/rerender can be noticeable. Memoize by graphData and getFormattedAddress.
- const searchGroups = (() => { + const searchGroups = useMemo(() => { if (!graphData) return []; return [ { type: "agent", icon: Users, heading: "Agents", items: Array.from( new Map( graphData.agents.map((agent) => [ agent.accountId, { id: agent.accountId, displayName: agent.name || smallAddress(agent.accountId), subtitle: `${agent.role} • ${smallAddress(agent.accountId)}`, searchText: `${agent.accountId} ${agent.name} ${agent.role}`.toLowerCase(), }, ]), ).values(), ), }, { type: "stream", icon: Zap, heading: "Stream Permissions", items: Array.from( new Map( graphData.permissions.emission.map((permission) => [ permission.id, { id: `permission-${permission.id}`, displayName: "Stream Permission", subtitle: `From: ${getFormattedAddress(permission.delegatorAccountId, 4)} → To: ${ permission.distributionTargets?.length ? `${permission.distributionTargets.length} recipients` : getFormattedAddress(permission.recipientAccountId, 4) }`, searchText: `${permission.id} ${permission.delegatorAccountId} stream emission`.toLowerCase(), }, ]), ).values(), ), }, { type: "namespace", icon: Package, heading: "Capability Permissions", items: Array.from( new Map( graphData.permissions.namespace.map((permission) => [ permission.id, { id: `permission-${permission.id}`, displayName: "Capability Permission", subtitle: `From: ${getFormattedAddress(permission.delegatorAccountId, 4)} → To: ${getFormattedAddress(permission.recipientAccountId, 4)}`, searchText: `${permission.id} ${permission.delegatorAccountId} ${permission.recipientAccountId} namespace capability`.toLowerCase(), }, ]), ).values(), ), }, { type: "signal", icon: Radio, heading: "Signals", items: Array.from( new Map( graphData.signals.map((signal) => [ signal.id, { id: `signal-${signal.id}`, displayName: signal.title, subtitle: `From: ${getFormattedAddress(signal.agentKey, 4)}`, searchText: `${signal.title} ${signal.description} ${signal.agentKey} signal`.toLowerCase(), }, ]), ).values(), ), }, ]; - })(); + }, [graphData, getFormattedAddress]);apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-permission.tsx (2)
46-90
: Aggregate duplicate stream weights and avoid repeating totals per stream
- When the same (targetAccountId, streamId) appears multiple times, the first weight wins and subsequent ones are ignored. Safer to accumulate.
- The total value badge is rendered inside the per-stream loop, so the same total is repeated for each stream row. Compute once per target (or show per-stream amounts).
for (const p of allPermissions) { if (p.permissions.permissionId !== permissionData.permissionId) continue; const target = p.emission_distribution_targets; if (!target?.targetAccountId) continue; const targetId = target.targetAccountId; const streamKey = target.streamId ?? "default"; if (!grouped.has(targetId)) grouped.set(targetId, new Map()); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const streams = grouped.get(targetId)!; - if (!streams.has(streamKey)) { - streams.set(streamKey, { - streamId: target.streamId, - weight: target.weight, - }); - } + const streams = grouped.get(targetId)!; + const existing = streams.get(streamKey); + if (existing) { + existing.weight += target.weight ?? 0; + } else { + streams.set(streamKey, { + streamId: target.streamId, + weight: target.weight ?? 0, + }); + } } - return Array.from(grouped.entries()).map(([targetAccountId, streams]) => { - const values = Array.from(streams.values()); - const hasSpecificStreams = values.some((s) => s.streamId); - // If there are specific streams, drop the default aggregate to avoid duplicated weights - if (hasSpecificStreams && streams.has("default")) { - streams.delete("default"); - } - return { - targetAccountId, - streams: Array.from(streams.values()), - }; - }); + return Array.from(grouped.entries()).map(([targetAccountId, streams]) => { + // If there are specific streams, drop the default aggregate to avoid duplicated weights + if (Array.from(streams.values()).some((s) => s.streamId) && streams.has("default")) { + streams.delete("default"); + } + const streamsArr = Array.from(streams.values()); + const totalWeight = streamsArr.reduce((acc, s) => acc + s.weight, 0); + return { targetAccountId, streams: streamsArr, totalWeight }; + });If you prefer, I can also move the “total value” badge outside the per-stream map and use entry.totalWeight.
93-107
: Stabilize accountIds to avoid unnecessary emissions fetchesallAccountIds is a fresh array every render. If the hook keys on reference equality, this can cause needless re-fetching. At minimum, return a sorted array for stable ordering.
- return Array.from(accounts); + return Array.from(accounts).sort();If the hook depends on reference equality, consider memoizing the array or keying the hook internally by a sorted-joined string.
apps/torus-portal/src/app/(pages)/(permission-graph)/_components/permission-graph-overview.tsx (1)
4-11
: Use theme tokens instead of hard-coded colorsSwap gray/white classes for design tokens to respect light/dark themes and future theming.
-const Bar = () => <div className="h-4 w-px bg-gray-800" />; +const Bar = () => <div className="h-4 w-px bg-border" />; const Stat = ({ label, value }: { label: string; value: number }) => ( <div className="flex items-center gap-2"> - <span className="text-xs font-medium text-gray-500">{label}</span> - <span className="text-sm font-semibold text-white">{value}</span> + <span className="text-xs font-medium text-muted-foreground">{label}</span> + <span className="text-sm font-semibold text-foreground">{value}</span> </div> );apps/torus-portal/src/app/(pages)/(permission-graph)/page.tsx (1)
45-67
: Replace 0ms setTimeout with queueMicrotask in effectThis PR’s goal is to remove 0ms timers; using a microtask here preserves ordering without a macrotask hop, avoids timer overhead, and aligns with your stated approach.
- // Use setTimeout to avoid direct setState in effect - const timer = setTimeout(updateSelection, 0); - return () => clearTimeout(timer); + // Defer to microtask to avoid synchronous setState while staying in the same tick + let cancelled = false; + queueMicrotask(() => { + if (!cancelled) updateSelection(); + }); + return () => { + cancelled = true; + };apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx (3)
144-168
: Sort immutably to avoid in-place mutation; consider memoizing if list is large.
.sort()
mutates the array. Sorting copies keeps data flow clearer. IfprocessedPermissions
can be large, re-sorting every render may regress perf—useMemo
keyed onprocessedPermissions
would help.- const sortPermissions = (permissions: typeof processedPermissions) => { - return permissions.sort((a, b) => { + const sortPermissions = (permissions: typeof processedPermissions) => { + return [...permissions].sort((a, b) => { // Sort by type: Capabilities first (namespace_permissions), then Emissions const aIsCapability = !!a.details?.namespace_permissions; const bIsCapability = !!b.details?.namespace_permissions; if (aIsCapability && !bIsCapability) return -1; if (!aIsCapability && bIsCapability) return 1; // Within same type, sort alphabetically by permission ID const aId = a.details?.permissions.permissionId ?? ""; const bId = b.details?.permissions.permissionId ?? ""; return aId.localeCompare(bId); }); };
308-316
: Prefer stable keys.Use the path value as the React key instead of the array index to avoid key collisions and preserve state on reorder.
- {paths.map((path, index) => ( - <div key={index}> + {paths.map((path) => ( + <div key={path}> <ShortenedCapabilityPath path={path} showTooltip={true} /> </div> ))}
461-487
: Inline element IIFE is okay; a small readability tweak helps.A simple renderer function avoids the IIFE pattern and reads cleaner with identical behavior.
- const PermissionsContent = (() => ( + const renderPermissionsContent = () => ( <ScrollArea className="h-[calc(100vh-26rem)]"> {processedPermissions.length > 0 ? ( <Accordion type="single" collapsible className="w-full"> {/* Delegated Permissions - only show if there are delegated permissions */} {groupedPermissions.delegated.length > 0 && renderPermissionGroup( groupedPermissions.delegated, "Delegated", <ArrowUpRight className="text-muted-foreground h-4 w-4" />, )} {/* Received Permissions - only show if there are received permissions */} {groupedPermissions.received.length > 0 && renderPermissionGroup( groupedPermissions.received, "Received", <ArrowDownLeft className="text-muted-foreground h-4 w-4" />, )} </Accordion> ) : ( <div className="mt-8 text-center text-gray-500"> No permissions found for this agent </div> )} </ScrollArea> - ))(); + ); @@ - {PermissionsContent} + {renderPermissionsContent()}Also applies to: 500-500
apps/torus-wallet/src/hooks/useTransactions.tsx (2)
29-31
: Optional: stabilize resetKey computation to avoid spurious resets.JSON.stringify on a filters object can reorder keys and trigger unnecessary resets. Consider a stable stringify (e.g., fast-json-stable-stringify) or building resetKey from a well-defined subset of sorted fields.
101-104
: Optional: refresh could reset totals/hasMore for consistency.Consider also resetting totalTransactions and hasMore on refresh to prevent brief stale counts.
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx
Show resolved
Hide resolved
…ompiler option in Next.js config for multiple apps
… dev changes - Merge conflict resolved in torus-bridge/next.config.mjs - Combined React Compiler flag with latest dev configurations - Fixed SEO metadata imports in wallet transfers page - All React Compiler configurations preserved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
apps/torus-portal/next.config.mjs (1)
5-7
: Gate the experimental React Compiler behind an env flag for safe rollout.This lets you flip it off quickly if regressions appear in one app.
Apply within the changed block:
- experimental: { - reactCompiler: true, - }, + experimental: { + reactCompiler: enableReactCompiler, + },And add near the top of the file (outside the hunk):
const enableReactCompiler = process.env.REACT_COMPILER === "true";apps/torus-wallet/next.config.mjs (1)
9-11
: Same: toggle React Compiler via env for quick rollback.- experimental: { - reactCompiler: true, - }, + experimental: { + reactCompiler: enableReactCompiler, + },Add once near the top:
const enableReactCompiler = process.env.REACT_COMPILER === "true";apps/torus-bridge/next.config.mjs (1)
20-22
: Guard experimental compiler with an env switch.- experimental: { - reactCompiler: true, - }, + experimental: { + reactCompiler: enableReactCompiler, + },Add near imports:
const enableReactCompiler = process.env.REACT_COMPILER === "true";apps/torus-governance/next.config.mjs (1)
5-7
: Env-gate the compiler; default can be on in CI/prod via env.- experimental: { - reactCompiler: true, - }, + experimental: { + reactCompiler: enableReactCompiler, + },Add at top:
const enableReactCompiler = process.env.REACT_COMPILER === "true";apps/torus-allocator/next.config.mjs (1)
5-7
: Env switch for experimental.reactCompiler.- experimental: { - reactCompiler: true, - }, + experimental: { + reactCompiler: enableReactCompiler, + },Add at top:
const enableReactCompiler = process.env.REACT_COMPILER === "true";apps/torus-page/next.config.mjs (1)
5-7
: Env-gate for safer staged rollout across apps.- experimental: { - reactCompiler: true, - }, + experimental: { + reactCompiler: enableReactCompiler, + },Add at top:
const enableReactCompiler = process.env.REACT_COMPILER === "true";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (7)
apps/torus-allocator/next.config.mjs
(1 hunks)apps/torus-bridge/next.config.mjs
(1 hunks)apps/torus-governance/next.config.mjs
(1 hunks)apps/torus-page/next.config.mjs
(1 hunks)apps/torus-portal/next.config.mjs
(1 hunks)apps/torus-wallet/next.config.mjs
(1 hunks)package.json
(1 hunks)
🔇 Additional comments (1)
package.json (1)
11-11
: Avoid double-enabling React Compiler; verify necessity of Babel plugin.package.json lists "babel-plugin-react-compiler": "19.1.0-rc.3" (matches npm dist-tag); react/react-dom are overridden to ^19.0.0 and Next is referenced as workspace "catalog". The repo search for Babel configs errored, so confirm the plugin is not also enabled via any Babel config or package.json "babel" field.
Run: rg -n --hidden --glob '!.git/' --glob '!node_modules/' 'babel-plugin-react-compiler' || true
If not referenced elsewhere, remove the devDependency to reduce supply-chain surface; if kept, pin to a stable version compatible with your React/Next stack.
- Downgraded several package versions to maintain compatibility and stability, including '@next/third-parties', '@react-three/drei', '@tanstack/react-query', and others. - Adjusted versions for '@trpc/client', '@trpc/react-query', and '@trpc/server' to align with the latest stable releases. - Updated '@types/node' and other dependencies to ensure consistency across the project.
- Ensured proper formatting by adding a newline at the end of the file to comply with coding standards.
- Updated several components in the torus-bridge and torus-governance applications to use setTimeout instead of queueMicrotask for state updates after client-side mounting and authentication checks. - This change improves compatibility and ensures that state updates are handled correctly in the React lifecycle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/torus-portal/src/hooks/use-blob-url.tsx (1)
12-15
: Replace setTimeout(0) with queueMicrotask; clear URL on null and guard against post-cleanup setState.
- setTimeout(0) contradicts the PR goal and risks calling setState after cleanup/unmount.
- When blob becomes null, url remains a revoked URL; set it to null.
Apply this diff within the changed lines:
- setTimeout(() => setUrl(objectUrl), 0); - return () => { - URL.revokeObjectURL(objectUrl); - }; + let cancelled = false; + queueMicrotask(() => { + if (!cancelled) setUrl(objectUrl); + }); + return () => { + cancelled = true; + URL.revokeObjectURL(objectUrl); + };And update the early return outside the selected range to clear stale state:
if (!blob) { setUrl(null); return; }Verify no remaining zero-delay timers in the repo:
#!/bin/bash # Find setTimeout(..., 0) usages rg -nP --type=ts --type=tsx -C2 'setTimeout\s*\(\s*[^,]+,\s*0\s*\)'
🧹 Nitpick comments (2)
apps/torus-bridge/next.config.mjs (2)
70-87
: Reconsider custom splitChunks; Next’s defaults are tuned and overrides can backfire.Manual cache groups can increase duplication or block Next’s heuristics. If you keep this, gate behind an env to allow quick rollback.
Apply this diff to gate the override:
- // Optimize bundle splitting - config.optimization.splitChunks = { + // Optimize bundle splitting (optional; gate for easy rollback) + if (process.env.ENABLE_CUSTOM_SPLIT_CHUNKS === "true") { + config.optimization.splitChunks = { chunks: "all", cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all", priority: 10, }, wallet: { test: /[\\/]node_modules[\\/](@solana|@cosmos-kit|@starknet|@hyperlane)[\\/]/, name: "wallet-vendors", chunks: "all", priority: 20, }, }, - }; + }; + }
3-6
: Remove stale jiti/env-loading comments or wire them up.These comments reference
createJiti
but it isn’t used; they add noise.Apply this diff:
-// Import env files to validate at build time. Use jiti so we can load .ts files in here. -// WARNING: ONLY NEEDED IF NEXT_PUBLIC_* VARIABLES ARE USED IN THE APP DIRECTLY -// createJiti(fileURLToPath(import.meta.url))("./src/env"); +// If you need build-time validation of NEXT_PUBLIC_* vars, wire up env loading here.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (8)
apps/torus-bridge/next.config.mjs
(3 hunks)apps/torus-bridge/src/app/_components/buttons/connect-aware-submit-button.tsx
(1 hunks)apps/torus-bridge/src/context/evm-wallet-provider.tsx
(1 hunks)apps/torus-bridge/src/context/solana-wallet-provider.tsx
(2 hunks)apps/torus-governance/hooks/use-sign-in.tsx
(2 hunks)apps/torus-portal/src/app/(pages)/(permission-graph)/page.tsx
(1 hunks)apps/torus-portal/src/hooks/use-blob-url.tsx
(1 hunks)package.json
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
- package.json
- apps/torus-bridge/src/app/_components/buttons/connect-aware-submit-button.tsx
- apps/torus-portal/src/app/(pages)/(permission-graph)/page.tsx
- apps/torus-governance/hooks/use-sign-in.tsx
- apps/torus-bridge/src/context/solana-wallet-provider.tsx
- apps/torus-bridge/src/context/evm-wallet-provider.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Follow docs/DOCUMENTATION_STYLE.md JSDoc conventions for all code documentation
Avoid top-level stateful singletons; use lazy initialization instead
For rustie enums, represent values as {VariantName: contents} and use rustie utilities (match, if_let) instead of switch/casts
Handle Result<T,E> from @torus-network/torus-utils/result via the [error, data] tuple pattern; do not use isOk/.success or try/catch for flow
Files:
apps/torus-portal/src/hooks/use-blob-url.tsx
**/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Access Drizzle entities via camelCase properties (e.g., permission.grantorKey), not snake_case
Files:
apps/torus-portal/src/hooks/use-blob-url.tsx
🧬 Code graph analysis (1)
apps/torus-bridge/next.config.mjs (5)
apps/torus-governance/next.config.mjs (1)
config
(2-25)apps/torus-page/next.config.mjs (1)
config
(2-15)apps/torus-wallet/next.config.mjs (1)
config
(6-39)apps/torus-allocator/next.config.mjs (1)
config
(2-20)apps/torus-portal/next.config.mjs (1)
config
(2-20)
⏰ 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). (9)
- GitHub Check: torus-bridge-pr-activate / clean-stale
- GitHub Check: torus-wallet-pr-activate / clean-stale
- GitHub Check: torus-governance-pr-activate / clean-stale
- GitHub Check: torus-allocator-pr-activate / clean-stale
- GitHub Check: torus-portal-pr-activate / clean-stale
- GitHub Check: torus-page-pr-activate / clean-stale
- GitHub Check: torus-cache-pr-activate / clean-stale
- GitHub Check: lint
- GitHub Check: typecheck
🔇 Additional comments (5)
apps/torus-bridge/next.config.mjs (5)
50-56
: Node protocol replacement for client builds looks good.Scoped to
!isServer
, regex is precise, and the replacement integrates cleanly with the fallbacks/ProvidePlugin once fixed.
12-12
: Enable React Compiler carefully (experimental).Good to keep aligned across apps; suggest gating with an env for quick disable if regressions appear.
Apply this minimal gate if you want the safety valve:
- reactCompiler: true, + reactCompiler: process.env.REACT_COMPILER === "true",Confirm: the repo adds
babel-plugin-react-compiler
and CI covers pages most affected by memoization changes.
57-61
: Good: explicitly disabling unpolyfillable Node modules on the client.Marking
fs
,net
,tls
, andchild_process
asfalse
avoids bloating the bundle or accidental shimming.
44-44
: No action needed (comment-only change).
26-33
: YAML/Turbopack: confirm Turbopack rule compatibility and address missing polyfills
- yaml-loader is present in package.json (FOUND).
- apps/torus-bridge/next.config.mjs (lines 26–33; also 90–95) uses turbopack.rules but the app's package.json lists Next as "catalog:" (no concrete version) — run in dev (Turbopack) or pin a concrete Next version (e.g., ^14/^15) to confirm the rules shape is honored.
- Missing Node polyfills in package.json: util, crypto-browserify, stream-browserify, events, process, buffer — add only if you hit build/runtime errors that require them.
…onfig - Deleted commented-out code for importing environment files in the Next.js configuration of both the torus-bridge and torus-wallet applications. - This cleanup enhances code readability and reduces clutter in the configuration files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/torus-bridge/next.config.mjs (1)
38-38
: Don’t ship production browser source maps by default—gate behind an env flag.Exposes source and bloats payloads if left on. Make it opt‑in.
- productionBrowserSourceMaps: true, + // Opt-in only to avoid leaking source + increasing payloads + productionBrowserSourceMaps: process.env.ENABLE_PROD_SOURCEMAPS === "true",
🧹 Nitpick comments (2)
apps/torus-bridge/next.config.mjs (2)
66-83
: Custom splitChunks can fight Next defaults—gate or measure.Safe to keep, but consider opt‑in to avoid regressions unless benchmarked.
- config.optimization.splitChunks = { + if (process.env.ENABLE_CUSTOM_SPLIT_CHUNKS === "true") { + config.optimization.splitChunks = { chunks: "all", cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: "vendors", chunks: "all", priority: 10, }, wallet: { test: /[\\/]node_modules[\\/](@solana|@cosmos-kit|@starknet|@hyperlane)[\\/]/, name: "wallet-vendors", chunks: "all", priority: 20, }, }, - }; + }; + }
86-90
: YAML loader present — de‑dupe turbopack vs webpack rule or document intent.
yaml-loader is declared in apps/torus-bridge/package.json (and appears in pnpm-lock.yaml). next.config.mjs registers it twice: turbopack.rules (".yaml"/".yml") and webpack.module.rules (test: /.ya?ml$/). If both are intentional (Turbopack vs Webpack), add an inline comment explaining why; otherwise remove the redundant rule.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
apps/torus-bridge/next.config.mjs
(3 hunks)apps/torus-wallet/next.config.mjs
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/torus-wallet/next.config.mjs
🧰 Additional context used
🧬 Code graph analysis (1)
apps/torus-bridge/next.config.mjs (5)
apps/torus-wallet/next.config.mjs (1)
config
(2-35)apps/torus-allocator/next.config.mjs (1)
config
(2-20)apps/torus-governance/next.config.mjs (1)
config
(2-25)apps/torus-portal/next.config.mjs (1)
config
(2-20)apps/torus-page/next.config.mjs (1)
config
(2-15)
⏰ 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). (9)
- GitHub Check: torus-governance-pr-activate / clean-stale
- GitHub Check: torus-governance-pr-activate / docker-build
- GitHub Check: torus-cache-pr-activate / docker-build
- GitHub Check: torus-allocator-pr-activate / docker-build
- GitHub Check: torus-bridge-pr-activate / docker-build
- GitHub Check: torus-wallet-pr-activate / docker-build
- GitHub Check: torus-wallet-pr-activate / clean-stale
- GitHub Check: torus-portal-pr-activate / docker-build
- GitHub Check: torus-page-pr-activate / docker-build
🔇 Additional comments (3)
apps/torus-bridge/next.config.mjs (3)
1-1
: Webpack fallbacks resolve to wrong paths — verification blocked (ripgrep skipped files)The verification script returned "No files were searched", so I couldn't confirm whether crypto-browserify, stream-browserify, events, process, buffer, and util exist in the workspace (apps/torus-bridge/next.config.mjs change depends on them).
- Re-run verification from repo root:
rg -n --no-heading -S 'crypto-browserify|stream-browserify|events|process|buffer|util' package.json package-lock.json yarn.lock pnpm-lock.yaml || true- If any are missing, install them and apply the suggested next.config.mjs changes: use createRequire(import.meta.url), add webpack.ProvidePlugin({ process: 'process/browser', Buffer: ['buffer','Buffer'] }), and set resolve.fallback to require.resolve(...) including buffer.
8-20
: Gate experimental React compiler behind an env and verify Next.js compatibility.experimental.reactCompiler is enabled in apps/*/next.config.mjs; root package.json includes babel-plugin-react-compiler@19.1.0-rc.3 and pnpm overrides pin react/react-dom to ^19.0.0, but Next.js versions are listed as "catalog:" (not resolved here) — confirm the actual Next.js release supports this experimental flag before enabling globally and roll out behind a feature gate.
Files: apps/*/next.config.mjs (e.g. apps/torus-bridge/next.config.mjs).
- reactCompiler: true, + reactCompiler: process.env.ENABLE_REACT_COMPILER === "true",
22-28
: Verify turbopack.rules is actually read by your Next version.Next’s turbopack supports a rules map and lists yaml-loader as a supported loader, but the config key was renamed from experimental.turbo/turbo → turbopack across releases — confirm the workspace Next version and that you run the dev server with Turbopack; apps/torus-bridge/next.config.mjs already defines turbopack.rules and also adds a webpack YAML-loader fallback (keep the webpack rule for Webpack builds).
…ider management - Updated the ProviderRenderer component in the torus-bridge application to handle providers with props, allowing for more flexible component rendering. - Introduced a createProviderWithProps utility function to streamline the creation of provider components with associated props. - Refactored the AppContextProvider to utilize the new provider structure, improving readability and maintainability of the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (9)
apps/torus-bridge/src/context/evm-wallet-provider.tsx (4)
129-129
: Re-init trigger may miss upstream chain-set changes.If multiProvider’s identity is stable while its known chains change internally, this memo won’t re-run. Consider keying off a stable “version” or the known chain names for safer invalidation.
Apply:
- }, [multiProvider]); + }, [multiProvider, /* safer: */ multiProvider.getKnownChainNames?.()?.join("|")]);If getKnownChainNames isn’t cheap, expose a cheap version/timestamp instead.
155-155
: Depend directly on token list to avoid stale initialChain.Depending on warpCore (object) risks missing updates if tokens mutate without reference change.
Apply:
- }, [multiProvider, warpCore]); + }, [multiProvider, warpCore.tokens]);If tokens can mutate in place, also include a light key:
+ }, [multiProvider, warpCore.tokens, warpCore.tokens.length]);
82-90
: Runtime guards and theme memo (optional).
- createConfig.client assumes at least one RPC URL; add a defensive check to avoid undefined access.
- midnightTheme object is recreated each render; memoize to reduce churn (minor).
client({ chain }) { - const transport = http(chain.rpcUrls.default.http[0]); + const url = chain.rpcUrls.default.http[0]; + if (!url) throw new Error(`No HTTP RPC URL for chain ${chain.id}`); + const transport = http(url); return createClient({ chain, transport }); },- return ( + const theme = useMemo( + () => + midnightTheme({ + accentColor: "#A7AFBE", + borderRadius: "small", + fontStack: "system", + }), + [], + ); + return ( <WagmiProvider config={wagmiConfig}> <RainbowKitProvider - theme={midnightTheme({ - accentColor: "#A7AFBE", - borderRadius: "small", - fontStack: "system", - })} + theme={theme} initialChain={initialChain} >Also applies to: 164-170
101-104
: Add concise JSDoc for exported components.Per docs/DOCUMENTATION_STYLE.md, add brief JSDoc for initWagmi and EvmWalletProvider (props, behavior, errors).
Also applies to: 161-174
apps/torus-bridge/src/app/_components/provider-renderer.tsx (4)
10-10
: Fix lint: avoid any in ProviderArray.Use unknown to satisfy the lint rule and preserve intent (heterogeneous providers).
-type ProviderArray = ProviderItem<any>[]; +type ProviderArray = ProviderItem<unknown>[];
12-21
: Null guard in type guard to prevent runtime TypeError."in" on null throws. Add provider !== null.
- return ( - typeof provider === "object" && + return ( + typeof provider === "object" && + provider !== null && "component" in provider && "props" in provider );
43-51
: Fix lint: avoid any in createProviderWithProps generic.Swap any for unknown and keep props inference via React.ComponentProps.
-export function createProviderWithProps<T extends ComponentType<any>>( +export function createProviderWithProps<T extends ComponentType<unknown>>( component: T, props: Omit<React.ComponentProps<T>, "children">, ): { component: T; props: Omit<React.ComponentProps<T>, "children">; } { return { component, props }; }Please re-run lint after this change.
1-1
: Add minimal JSDoc on exported APIs.Add short descriptions and param docs for ProviderRenderer and createProviderWithProps per repo style.
Also applies to: 28-31, 43-51
apps/torus-bridge/src/context/app-context-provider.tsx (1)
26-26
: Return null for SSR guard.Returning an empty div injects an extra node; prefer null to avoid layout/hydration quirks.
- if (useIsSsr()) return <div></div>; + if (useIsSsr()) return null;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/torus-bridge/src/app/_components/provider-renderer.tsx
(1 hunks)apps/torus-bridge/src/context/app-context-provider.tsx
(2 hunks)apps/torus-bridge/src/context/evm-wallet-provider.tsx
(3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Follow docs/DOCUMENTATION_STYLE.md JSDoc conventions for all code documentation
Avoid top-level stateful singletons; use lazy initialization instead
For rustie enums, represent values as {VariantName: contents} and use rustie utilities (match, if_let) instead of switch/casts
Handle Result<T,E> from @torus-network/torus-utils/result via the [error, data] tuple pattern; do not use isOk/.success or try/catch for flow
Files:
apps/torus-bridge/src/context/app-context-provider.tsx
apps/torus-bridge/src/app/_components/provider-renderer.tsx
apps/torus-bridge/src/context/evm-wallet-provider.tsx
**/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Access Drizzle entities via camelCase properties (e.g., permission.grantorKey), not snake_case
Files:
apps/torus-bridge/src/context/app-context-provider.tsx
apps/torus-bridge/src/app/_components/provider-renderer.tsx
apps/torus-bridge/src/context/evm-wallet-provider.tsx
🧬 Code graph analysis (1)
apps/torus-bridge/src/context/app-context-provider.tsx (3)
apps/torus-bridge/src/app/_components/provider-renderer.tsx (2)
ProviderRenderer
(28-41)createProviderWithProps
(43-51)packages/torus-provider/src/torus-provider.tsx (1)
TorusProvider
(58-264)packages/query-provider/src/query-provider.tsx (1)
ReactQueryProvider
(24-36)
🪛 GitHub Check: lint
apps/torus-bridge/src/app/_components/provider-renderer.tsx
[failure] 43-43:
Unexpected any. Specify a different type
[failure] 10-10:
Unexpected any. Specify a different type
⏰ 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). (8)
- GitHub Check: torus-bridge-pr-activate / clean-stale
- GitHub Check: torus-portal-pr-activate / clean-stale
- GitHub Check: torus-wallet-pr-activate / clean-stale
- GitHub Check: torus-page-pr-activate / clean-stale
- GitHub Check: torus-governance-pr-activate / clean-stale
- GitHub Check: torus-allocator-pr-activate / clean-stale
- GitHub Check: torus-allocator-pr-activate / docker-build
- GitHub Check: torus-cache-pr-activate / clean-stale
🔇 Additional comments (6)
apps/torus-bridge/src/context/evm-wallet-provider.tsx (2)
25-25
: Import cleanup looks good.Dropping useEffect/useState and relying on memoization aligns with the new SSR guard at the app level.
82-90
: Wagmi createConfig client({ chain }) — compatible with @wagmi/core v2
pnpm-lock.yaml shows @wagmi/core resolved to 2.20.2 (2.16.3 present transitively); @wagmi/core v2 supports createConfig({ client({ chain }) { return createClient(...) } }) so the snippet is compatible. (wagmi.sh)apps/torus-bridge/src/app/_components/provider-renderer.tsx (1)
32-41
: Provider folding logic is clean and readable.The reduceRight composition and props-aware branch look good.
apps/torus-bridge/src/context/app-context-provider.tsx (3)
9-12
: New provider composition import looks good.Importing createProviderWithProps and ProviderRenderer matches the new composition model.
29-41
: Provider order LGTM; minor env safety check.Ordering places Torus and Query providers before consumers, which is correct. Ensure env() is safe on the client for NEXT_PUBLIC_* vars.
If env() can throw on missing keys, confirm both NEXT_PUBLIC_TORUS_RPC_URL and NEXT_PUBLIC_TORUS_CACHE_URL are defined in all deploy envs.
43-47
: Child layout OK.Header/Container/Toaster/Footer placement looks consistent with prior structure.
…Renderer - Added eslint-disable comments to suppress warnings for the use of 'any' in the ProviderRenderer component of the torus-bridge application. - This change improves code clarity while maintaining flexibility in provider management.
…ment - Updated the TransferDetails component in the torus-bridge application to utilize useRef for tracking previous transfer lengths, improving the logic for displaying transfer details. - Enhanced the useLayoutEffect hook to prevent unnecessary updates and ensure the modal opens only when new transfers are detected. - Modified the TransfersDetailsDialog to handle open state changes more effectively, improving user experience during transfer interactions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx (1)
71-121
: Guard async effect to prevent stale updates and setState on unmounted.Add a cancel flag and cleanup. This avoids older resolutions clobbering newer state and warnings after unmount. (Same as a prior review on this block.)
useEffect(() => { + let cancelled = false; const getMessageUrls = async () => { setFromUrl(""); setToUrl(""); setOriginTxUrl(""); if (originTxHash) { - const [txUrlError, originTxUrl] = trySync(() => + const [txUrlError, originTxUrl] = trySync(() => multiProvider.tryGetExplorerTxUrl(origin, { hash: originTxHash }), ); if (txUrlError !== undefined) { logger.error( `Error getting transaction URL for hash ${originTxHash}:`, txUrlError, ); - } else if (originTxUrl) { - setOriginTxUrl(fixDoubleSlash(originTxUrl)); + } else if (originTxUrl && !cancelled) { + setOriginTxUrl(fixDoubleSlash(originTxUrl)); } } const [fromUrlPromise, toUrlPromise] = [ multiProvider.tryGetExplorerAddressUrl(origin, sender), multiProvider.tryGetExplorerAddressUrl(destination, recipient), ]; const [fromUrlError, fromUrl] = await tryAsync(fromUrlPromise); if (fromUrlError !== undefined) { logger.error( `Error getting explorer URL for sender ${sender}:`, fromUrlError, ); - } else if (fromUrl) { - setFromUrl(fixDoubleSlash(fromUrl)); + } else if (fromUrl && !cancelled) { + setFromUrl(fixDoubleSlash(fromUrl)); } const [toUrlError, toUrl] = await tryAsync(toUrlPromise); if (toUrlError !== undefined) { logger.error( `Error getting explorer URL for recipient ${recipient}:`, toUrlError, ); - } else if (toUrl) { - setToUrl(fixDoubleSlash(toUrl)); + } else if (toUrl && !cancelled) { + setToUrl(fixDoubleSlash(toUrl)); } }; getMessageUrls().catch((err) => { logger.error("Error getting message URLs for details modal", err); }); + return () => { + cancelled = true; + }; }, [sender, recipient, originTxHash, multiProvider, origin, destination]);
🧹 Nitpick comments (2)
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx (1)
78-89
: Avoid shadowing state variable name.Local
originTxUrl
shadows the state setter target, which is easy to misread. Rename the local totxUrl
.- const [txUrlError, originTxUrl] = trySync(() => + const [txUrlError, txUrl] = trySync(() => multiProvider.tryGetExplorerTxUrl(origin, { hash: originTxHash }), ); @@ - } else if (originTxUrl) { - setOriginTxUrl(fixDoubleSlash(originTxUrl)); + } else if (txUrl) { + setOriginTxUrl(fixDoubleSlash(txUrl)); }apps/torus-bridge/src/app/_components/transfer-details/index.tsx (1)
32-35
: Guard microtask setState against unmount.Queueing a microtask can still fire after unmount. Add an
isMounted
ref and short‑circuit inside the microtask.- queueMicrotask(() => { - setSelectedTransfer(latestTransfer); - setIsModalOpen(true); - }); + queueMicrotask(() => { + if (!isMounted.current) return; + setSelectedTransfer(latestTransfer); + setIsModalOpen(true); + });Add lifecycle guard (outside the effect):
-import { useLayoutEffect, useRef, useState } from "react"; +import { useEffect, useLayoutEffect, useRef, useState } from "react"; @@ - const prevTransfersLength = useRef(0); + const prevTransfersLength = useRef(0); + const isMounted = useRef(true); + useEffect(() => { + return () => { + isMounted.current = false; + }; + }, []);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx
(2 hunks)apps/torus-bridge/src/app/_components/transfer-details/index.tsx
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Follow docs/DOCUMENTATION_STYLE.md JSDoc conventions for all code documentation
Avoid top-level stateful singletons; use lazy initialization instead
For rustie enums, represent values as {VariantName: contents} and use rustie utilities (match, if_let) instead of switch/casts
Handle Result<T,E> from @torus-network/torus-utils/result via the [error, data] tuple pattern; do not use isOk/.success or try/catch for flow
Files:
apps/torus-bridge/src/app/_components/transfer-details/index.tsx
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx
**/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Access Drizzle entities via camelCase properties (e.g., permission.grantorKey), not snake_case
Files:
apps/torus-bridge/src/app/_components/transfer-details/index.tsx
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx
🧬 Code graph analysis (2)
apps/torus-bridge/src/app/_components/transfer-details/index.tsx (1)
apps/torus-bridge/src/utils/store.ts (1)
useStore
(58-175)
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx (2)
packages/torus-utils/src/try-catch.ts (2)
trySync
(40-42)tryAsync
(97-101)apps/torus-bridge/src/utils/logger.ts (1)
logger
(1-8)
⏰ 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). (8)
- GitHub Check: torus-bridge-pr-activate / docker-build
- GitHub Check: torus-cache-pr-activate / docker-build
- GitHub Check: torus-wallet-pr-activate / docker-build
- GitHub Check: torus-wallet-pr-activate / clean-stale
- GitHub Check: torus-allocator-pr-activate / docker-build
- GitHub Check: torus-portal-pr-activate / docker-build
- GitHub Check: torus-governance-pr-activate / docker-build
- GitHub Check: torus-page-pr-activate / docker-build
🔇 Additional comments (2)
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx (1)
150-150
: LGTM on controlled dialog close behavior.Using
onOpenChange={(open) => !open && onClose()}
correctly delegates close events to the parent.apps/torus-bridge/src/app/_components/transfer-details/index.tsx (1)
21-25
: Initialization flow reads clean.Skipping the first render while initializing the baseline is correct.
apps/torus-bridge/src/app/_components/transfer-details/_components/transfer-details-dialog.tsx
Show resolved
Hide resolved
- Added a new layout component for the DAO dashboard in the torus-governance application, enhancing the structure for displaying dashboard content. - Introduced SEO metadata generation for the DAO dashboard, improving search engine visibility and user engagement. - Updated the next-env.d.ts file to include route type definitions for better TypeScript support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
apps/torus-governance/src/app/(pages)/dao-dashboard/page.tsx (1)
10-12
: Optionally lazy‑load tab panels to reduce initial JS.Defer loading of non‑active panels via
next/dynamic
. Also drop statickey
props onTabsContent
(not part of a list).+import dynamic from "next/dynamic"; -import AgentHealthTab from "./_components/agent-health-tab/agent-health-tab"; -import DaoApplicationsTab from "./_components/dao-applications-tab"; -import DashboardTab from "./_components/dashboard-tab/dashboard"; +const DashboardTab = dynamic(() => import("./_components/dashboard-tab/dashboard")); +const AgentHealthTab = dynamic(() => import("./_components/agent-health-tab/agent-health-tab")); +const DaoApplicationsTab = dynamic(() => import("./_components/dao-applications-tab")); - <TabsContent value="dashboard" key="dashboard-tab"> + <TabsContent value="dashboard"> <DashboardTab /> </TabsContent> - <TabsContent value="agent-health" key="agent-health-tab"> + <TabsContent value="agent-health"> <AgentHealthTab /> </TabsContent> - <TabsContent value="dao-applications" key="dao-applications-tab"> + <TabsContent value="dao-applications"> <DaoApplicationsTab /> </TabsContent>Also applies to: 36-44
apps/torus-governance/src/app/(pages)/dao-dashboard/layout.tsx (1)
1-2
: Add explicit return type forgenerateMetadata
.Minor type clarity improvement aligned with our TS docs.
+import type { Metadata } from "next"; import { createSeoMetadata } from "@torus-ts/ui/components/seo"; import { env } from "~/env"; -export function generateMetadata() { +export function generateMetadata(): Metadata {Also applies to: 4-5
apps/torus-governance/next-env.d.ts (1)
3-3
: Prefer glob include to future‑proof against file name changes.Hardcoding
routes.d.ts
can break when Next changes generated file names. Use the commonly recommended glob instead.Apply this diff:
-/// <reference path="./.next/types/routes.d.ts" /> +/// <reference path="./.next/types/**/*.ts" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/torus-governance/next-env.d.ts
(1 hunks)apps/torus-governance/src/app/(pages)/dao-dashboard/layout.tsx
(1 hunks)apps/torus-governance/src/app/(pages)/dao-dashboard/page.tsx
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Follow docs/DOCUMENTATION_STYLE.md JSDoc conventions for all code documentation
Avoid top-level stateful singletons; use lazy initialization instead
For rustie enums, represent values as {VariantName: contents} and use rustie utilities (match, if_let) instead of switch/casts
Handle Result<T,E> from @torus-network/torus-utils/result via the [error, data] tuple pattern; do not use isOk/.success or try/catch for flow
Files:
apps/torus-governance/src/app/(pages)/dao-dashboard/layout.tsx
apps/torus-governance/next-env.d.ts
apps/torus-governance/src/app/(pages)/dao-dashboard/page.tsx
**/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Access Drizzle entities via camelCase properties (e.g., permission.grantorKey), not snake_case
Files:
apps/torus-governance/src/app/(pages)/dao-dashboard/layout.tsx
apps/torus-governance/src/app/(pages)/dao-dashboard/page.tsx
🧠 Learnings (2)
📚 Learning: 2025-07-27T01:55:40.478Z
Learnt from: CR
PR: renlabs-dev/torus-ts#0
File: packages/torus-sdk-ts/src/chain/CLAUDE.md:0-0
Timestamp: 2025-07-27T01:55:40.478Z
Learning: Applies to packages/torus-sdk-ts/src/chain/**/*.{ts,tsx} : Document all exports with JSDoc comments.
Applied to files:
apps/torus-governance/next-env.d.ts
📚 Learning: 2025-07-19T17:44:15.833Z
Learnt from: CR
PR: renlabs-dev/torus-ts#0
File: packages/dsl/CLAUDE.md:0-0
Timestamp: 2025-07-19T17:44:15.833Z
Learning: Applies to packages/dsl/src/types.ts : All core type definitions for the DSL must be defined in a single source of truth file: /packages/dsl/src/types.ts
Applied to files:
apps/torus-governance/next-env.d.ts
🧬 Code graph analysis (1)
apps/torus-governance/src/app/(pages)/dao-dashboard/layout.tsx (1)
packages/ui/src/components/seo.tsx (1)
createSeoMetadata
(67-156)
🔇 Additional comments (4)
apps/torus-governance/src/app/(pages)/dao-dashboard/page.tsx (1)
1-1
: Client page OK — metadata owned by layout. Verified: apps/torus-governance/src/app/(pages)/dao-dashboard/page.tsx has no generateMetadata export; apps/torus-governance/src/app/(pages)/dao-dashboard/layout.tsx exports generateMetadata (line 4).apps/torus-governance/src/app/(pages)/dao-dashboard/layout.tsx (1)
4-20
: Confirm BASE_URL is set and absolutegenerateMetadata (apps/torus-governance/src/app/(pages)/dao-dashboard/layout.tsx) uses env("BASE_URL") but a repo-wide search returned no matches for BASE_URL — add BASE_URL to all envs (absolute URL) or supply a safe absolute fallback so OG/canonical links are correct.
apps/torus-governance/next-env.d.ts (2)
3-3
: LGTM: Adds typed routes to TS context.This aligns with Next’s typed‑routes pattern and has no runtime impact.
3-3
: Ensure CI generates Next .next/types before running tsc — verifyjust typecheck
apps/torus-governance/next-env.d.ts references "./.next/types/routes.d.ts" and apps/torus-governance/package.json defines "typecheck": "tsc --noEmit". CI runs
just typecheck
(.github/workflows/ci.yml → Typecheck step) but no Justfile was found in the repo — confirm whatjust typecheck
actually executes. If it does not generate Next's .next/types first, either:
- run
next build
(or Next typegen) for affected apps in CI before runningtsc
, or- remove/guard the triple-slash reference (or commit a minimal stub .next/types/routes.d.ts) so
tsc --noEmit
won't fail.Files to check: apps/torus-governance/next-env.d.ts, apps/torus-governance/package.json, .github/workflows/ci.yml.
- Refactored multiple components across the torus-bridge and torus-governance applications to utilize useMemo for memoizing values, enhancing performance by preventing unnecessary recalculations. - Updated the token list modal, transfer token form, agent applications hook, and various other components to improve rendering efficiency and state management. - Adjusted ESLint configuration to disable the 'preserve-manual-memoization' rule, allowing for clearer memoization practices in the codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx (1)
196-201
: Accordion item “value”/key collisions possible across different permissions of the same source/targetUsing
${sourceId}-${targetId}
for both key and value will collide if multiple permissions exist between the same pair (e.g., capability and emission). Use the permissionId to guarantee uniqueness.- <AccordionItem - key={`${sourceId}-${targetId}`} - value={`${sourceId}-${targetId}`} + <AccordionItem + key={`cap-${details?.permissions.permissionId ?? `${sourceId}-${targetId}`}`} + value={`cap-${details?.permissions.permissionId ?? `${sourceId}-${targetId}`}`} className="bg-accent mb-2 border" >- <AccordionItem - key={`${sourceId}-${targetId}`} - value={`${sourceId}-${targetId}`} + <AccordionItem + key={`emi-${details?.permissions.permissionId ?? `${sourceId}-${targetId}`}`} + value={`emi-${details?.permissions.permissionId ?? `${sourceId}-${targetId}`}`} className="bg-accent mb-2 border" >Also applies to: 338-343
🧹 Nitpick comments (6)
apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx (5)
462-488
: Replace IIFE element with a memoized element and lowercase name to avoid component confusionThe IIFE pre-renders every render and
PermissionsContent
looks like a component but is an element. Memoize the element and rename for clarity.- const PermissionsContent = (() => ( + const permissionsContentEl = useMemo(() => ( <ScrollArea className="h-[calc(100vh-26rem)]"> {processedPermissions.length > 0 ? ( <Accordion type="single" collapsible className="w-full"> {/* Delegated Permissions - only show if there are delegated permissions */} {groupedPermissions.delegated.length > 0 && renderPermissionGroup( groupedPermissions.delegated, "Delegated", <ArrowUpRight className="text-muted-foreground h-4 w-4" />, )} {/* Received Permissions - only show if there are received permissions */} {groupedPermissions.received.length > 0 && renderPermissionGroup( groupedPermissions.received, "Received", <ArrowDownLeft className="text-muted-foreground h-4 w-4" />, )} </Accordion> ) : ( <div className="mt-8 text-center text-gray-500"> No permissions found for this agent </div> )} </ScrollArea> - ))(); + ), [groupedPermissions, processedPermissions.length]);- {PermissionsContent} + {permissionsContentEl}Also applies to: 501-501
82-142
: Memoize processedPermissions; otherwise groupedPermissions useMemo always recomputes
processedPermissions
is recreated each render viamap
, sogroupedPermissions
’s dependency changes every time. Memoize the mapping to unlock the intended optimization.- const processedPermissions = nodePermissions.map((permission) => { + const processedPermissions = useMemo(() => nodePermissions.map((permission) => { // Extract permission ID from node ID if it's a permission node const getPermissionId = (nodeId: string | number | object | undefined) => { if (!nodeId) return null; const id = typeof nodeId === "object" && "id" in nodeId ? nodeId.id : nodeId; if (typeof id !== "string") return null; return id.startsWith("permission-") ? id.replace("permission-", "") : null; }; const sourcePermissionId = getPermissionId(permission.source); const targetPermissionId = getPermissionId(permission.target); // Try to find by permission ID first (most reliable) const permissionId = sourcePermissionId ?? targetPermissionId; const details = allPermissions?.find((p) => { if (permissionId) { return p.permissions.permissionId === permissionId; } // Fallback to account ID matching (for non-permission nodes) const sourceId = typeof permission.source === "object" && "id" in permission.source ? permission.source.id : permission.source; const targetId = typeof permission.target === "object" && "id" in permission.target ? permission.target.id : permission.target; return ( p.permissions.grantorAccountId === sourceId && p.permissions.granteeAccountId === targetId ); }); const isOutgoing = permission.type === "outgoing"; const connectedNode = graphData?.nodes.find( (n) => n.id === (isOutgoing ? permission.target : permission.source), ); const connectedAddress = connectedNode?.fullAddress ?? connectedNode?.id ?? ""; const sourceId = typeof permission.source === "object" ? permission.source.id : permission.source; const targetId = typeof permission.target === "object" ? permission.target.id : permission.target; return { permission, details, isOutgoing, connectedAddress, sourceId, targetId, }; - }); + }), [nodePermissions, allPermissions, graphData?.nodes]);
309-317
: Prefer stable, semantic keys for pathsUse
path
as the key instead of the array index to avoid unnecessary re-renders when order changes.- {paths.map((path, index) => ( - <div key={index}> + {paths.map((path) => ( + <div key={path}> <ShortenedCapabilityPath path={path} showTooltip={true} /> </div> ))}
66-68
: Remove eslint-disable by typing the map paramNarrow
target
to a safe shape to dropno-unsafe-member-access
.- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - .map((target) => target?.targetAccountId as string | undefined) + .map( + (target: { targetAccountId?: string } | null | undefined) => + target?.targetAccountId + )
31-36
: Add minimal JSDoc per repo conventionsDocument the component and props to align with docs/DOCUMENTATION_STYLE.md.
+/** + * Node details pane for permissions/signals in the permission graph sheet. + * Renders delegated/received permission groups and signals for the selected node. + */ export function NodeDetailsCard({Also applies to: 38-43
tooling/eslint/react.js (1)
15-15
: Set react-hooks/preserve-manual-memoization to "warn" and enable the React Compiler lint rule.tooling/eslint/package.json shows the plugin is on the RC channel (so the rule exists); use "warn" to preserve signal without failing CI and enable "react-hooks/react-compiler" when adopting the React Compiler. Ensure eslint-plugin-react-hooks >= 6.0.0-rc.1.
File: tooling/eslint/react.js (around line 15)
- "react-hooks/preserve-manual-memoization": "off", + "react-hooks/preserve-manual-memoization": "warn",
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (17)
apps/torus-bridge/src/app/_components/tokens/token-list-modal.tsx
(0 hunks)apps/torus-bridge/src/app/_components/transfer-token/_components/transfer-token-form.tsx
(0 hunks)apps/torus-governance/hooks/use-agent-applications.tsx
(1 hunks)apps/torus-governance/hooks/use-agent-health.ts
(0 hunks)apps/torus-governance/src/app/_components/comments/view-comment.tsx
(2 hunks)apps/torus-governance/src/app/_components/filter-content.tsx
(0 hunks)apps/torus-portal/src/app/(pages)/(permission-graph)/_components/force-graph/use-graph-data.ts
(0 hunks)apps/torus-portal/src/app/(pages)/(permission-graph)/_components/force-graph/use-graph-interactions.ts
(1 hunks)apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx
(3 hunks)apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-permission.tsx
(0 hunks)apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-signals-accordion.tsx
(0 hunks)apps/torus-portal/src/app/(pages)/(permission-graph)/_components/permission-graph-command.tsx
(0 hunks)apps/torus-portal/src/app/(pages)/capabilities/register-capability/_components/create-capability-prefix-field.tsx
(0 hunks)apps/torus-portal/src/app/_components/address-field.tsx
(0 hunks)apps/torus-portal/src/hooks/use-weekly-usd.ts
(1 hunks)apps/torus-wallet/next-env.d.ts
(1 hunks)tooling/eslint/react.js
(1 hunks)
💤 Files with no reviewable changes (10)
- apps/torus-portal/src/app/_components/address-field.tsx
- apps/torus-portal/src/app/(pages)/capabilities/register-capability/_components/create-capability-prefix-field.tsx
- apps/torus-portal/src/app/(pages)/(permission-graph)/_components/permission-graph-command.tsx
- apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-signals-accordion.tsx
- apps/torus-governance/src/app/_components/filter-content.tsx
- apps/torus-bridge/src/app/_components/tokens/token-list-modal.tsx
- apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-permission.tsx
- apps/torus-governance/hooks/use-agent-health.ts
- apps/torus-bridge/src/app/_components/transfer-token/_components/transfer-token-form.tsx
- apps/torus-portal/src/app/(pages)/(permission-graph)/_components/force-graph/use-graph-data.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/torus-governance/src/app/_components/comments/view-comment.tsx
- apps/torus-portal/src/app/(pages)/(permission-graph)/_components/force-graph/use-graph-interactions.ts
- apps/torus-governance/hooks/use-agent-applications.tsx
- apps/torus-portal/src/hooks/use-weekly-usd.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Follow docs/DOCUMENTATION_STYLE.md JSDoc conventions for all code documentation
Avoid top-level stateful singletons; use lazy initialization instead
For rustie enums, represent values as {VariantName: contents} and use rustie utilities (match, if_let) instead of switch/casts
Handle Result<T,E> from @torus-network/torus-utils/result via the [error, data] tuple pattern; do not use isOk/.success or try/catch for flow
Files:
apps/torus-wallet/next-env.d.ts
apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx
**/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Access Drizzle entities via camelCase properties (e.g., permission.grantorKey), not snake_case
Files:
apps/torus-portal/src/app/(pages)/(permission-graph)/_components/graph-sheet/graph-sheet-details/graph-sheet-details-card.tsx
🧠 Learnings (1)
📚 Learning: 2025-07-19T17:44:15.833Z
Learnt from: CR
PR: renlabs-dev/torus-ts#0
File: packages/dsl/CLAUDE.md:0-0
Timestamp: 2025-07-19T17:44:15.833Z
Learning: Applies to packages/dsl/src/types.ts : All core type definitions for the DSL must be defined in a single source of truth file: /packages/dsl/src/types.ts
Applied to files:
apps/torus-wallet/next-env.d.ts
🔇 Additional comments (1)
apps/torus-wallet/next-env.d.ts (1)
3-3
: LGTM — confirm typed routes are generated in CIapps//next-env.d.ts (apps/torus-wallet, torus-portal, torus-governance, torus-bridge, torus-page) reference .next/types/routes.d.ts; no typedRoutes found in any apps' next.config. and package.json shows "next": "catalog:" (Next managed centrally). Ensure CI runs a Next step that generates ./.next/types/routes.d.ts (or enable typedRoutes in config) before running tsc --noEmit on clean checkouts.
…portal applications - Adjusted import statements for better readability in the use-agent-applications hook and view-comment component. - Enhanced the useWeeklyUsdCalculation hook by formatting the dependency array for improved clarity. - These changes contribute to a cleaner codebase and maintainable structure across the applications.
rules: { | ||
...reactPlugin.configs["jsx-runtime"].rules, | ||
...hooksPlugin.configs.recommended.rules, | ||
"react-hooks/preserve-manual-memoization": "off", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left it off for now because it doesn't seem to be that simple to solve this problem, by leaving this rule activated and removing both useCallback and useMemo (bugs occur due to lack of memorization, react-compiler support doesn't seem to be working 100% correctly), I did some research and tried to solve it via LLM but was unsuccessful so I think we can revisit this in the future when it is no longer experimental.
…mpatibility issues - Temporarily turned off the 'react-hooks/preserve-manual-memoization' rule in the ESLint configuration for React. - This change addresses compatibility concerns with the experimental react-compiler in the Next.js ecosystem. - Future updates will revisit this deactivation once the compatibility issues are resolved.
Summary by CodeRabbit
Refactor
Bug Fixes
Chores