feat(rabe_connector): implement secure persistent caching for active addresses - #342
Merged
godamongstmen897 merged 232 commits intoSep 1, 2026
Conversation
…inner_skeleton - Replace hardcoded gray-* Tailwind classes with semantic design tokens: * bg-gray-900 -> bg-surface-card * bg-gray-800 -> bg-surface-field (content placeholders) * border-gray-800 -> border-border-strong * bg-gray-700 -> bg-border-subtle (nested placeholders / contrast layer) - Add data-testid attributes to all skeleton sections for testability - Add 19 comprehensive test cases covering: * Design token validation (no hardcoded gray-* classes remain) * Correct token-to-element mapping across container/header/stats/milestones * Component layout structure (grid, count, padding, animations) * Accessibility attributes (role=status, aria-live, sr-only, aria-hidden) All 436 tests (33 files) pass, including the 19 new assertions.
- Add DEFAULT_SIGNING_TIMEOUT_MS = 60_000 configurable constant - Add TxSignRequest interface, TxSignatureTimeoutError class, clearTxSensitiveMemory helper, and signTxWithTimeout function to app/lib/transactions.ts, matching the setTimeout + Promise.race pattern used by all other connector helpers in the codebase - Wire signTxWithTimeout into submitContractTransaction via optional signingTimeoutMs param (defaults to the constant); on timeout the operation is aborted and any sensitive payload memory is zeroed - Add __tests__/transactions_timeout.test.ts with 21 test cases covering: timeout fires, memory cleared, successful signing flow, pre-deadline no-early-fire, timer cleanup, error propagation, default constant, TxSignatureTimeoutError class, and clearTxSensitiveMemory helper
Adds app/components/TransactionSignerPanel.tsx — a wallet-agnostic sign-transaction interface that unblocks issue Goldii-locks#222 (RTL tests). - Parses supplied XDR on mount via useWalletMultiSigAssembly.parseStructure and displays a structure preview (source account, fee, operation count, existing signatures) - States: idle -> signing -> success | error | parse-error - Sign button delegates to hook.signTransaction(xdr, signTransaction) — no new XDR parsing or signing logic introduced - Retry button returns to idle on signing failure - Cancel/Dismiss calls onRejected() and resets state - onSigned, onRejected, onError callbacks for parent integration - Works for all four supported wallets (freighter, albedo, xbull, hana) through the unified useWalletMultiSigAssembly hook
- Replace hardcoded empty message with EmptyStateCard component - Display briefcase icon for job-related context - Show descriptive title and explanation text - Include role badges (Client, Freelancer, Arbiter) showing available participation options - Add comprehensive test coverage with 16 test cases - Ensure proper accessibility with region landmarks and aria-labels - Validates placeholder display under empty data states
…, desktop - Add responsive padding and spacing (px-3 sm:px-6) for mobile-first approach - Implement responsive typography scaling (text-xl sm:text-2xl md:text-3xl) - Stack layout vertically on mobile, horizontal on tablet/desktop - Apply responsive grid layouts (grid-cols-1 sm:grid-cols-2 lg:grid-cols-3) - Make search form full-width on mobile, inline on tablet+ - Add responsive gaps and margins throughout - Implement horizontal overflow handling for pagination on mobile - Reduce button padding and font sizes on mobile viewports - Add comprehensive responsive design test suite with 20 test cases - Validate layout at mobile (< 640px), tablet (640-1024px), desktop (> 1024px)
…yling - Add focus-visible ring-2 styling on all interactive elements (indigo-500) - Implement hover state transitions with smooth animations (transition-all duration-200) - Add active state styling for button press feedback - Style disabled buttons with opacity-50 and cursor-not-allowed - Prevent hover effects on disabled buttons (disabled:hover:bg-gray-900) - Apply ring-offset for focus states on dark background (ring-offset-gray-950) - Use inset focus ring on job expand buttons for better UX - Add focus-visible:outline-none to remove browser defaults - Implement smooth transitions on all state changes - Add comprehensive test suite with 25 test cases validating: - Search input focus and hover states - Search button focus, hover, and active states - Role filter button states and transitions - Job expand button interactive states - Pagination button states and disabled styling - Accessibility compliance and transitions
…vigation, semantic HTML)
…onSignerPanel - Move state declarations before closeModal callback (WalletSelectorModal) - Remove eslint-disable and add missing hook dependency (TransactionSignerPanel)
…addresses Add state serialization to rabe_connector so active wallet addresses survive page reload cycles. New exports: - RABE_CACHE_KEY: localStorage key for the cache entry - RabeActiveAddressCache: versioned interface (version, address, savedAt, network) - validateRabeAddressCache: strict runtime validation (address format, timestamp, network) - serializeRabeAddressCache / deserializeRabeAddressCache: JSON round-trip with validation on read-back; returns null on corrupt data - saveRabeAddressCache: writes to localStorage; SSR-safe; logs warning on QuotaExceededError via existing logRabeWarning - loadRabeAddressCache: reads + validates from localStorage; SSR-safe - clearRabeAddressCache: removes entry on disconnect; no-op if absent Tests: 33 new cases covering validation, serialization round-trips, and all localStorage integration scenarios (save/load/clear, overwrite, corrupt data, storage errors, timestamp bounds). All 376 existing tests continue to pass. TypeScript: 0 errors. Closes Goldii-locks#137
…ing-skeleton-stories feat: add Storybook stories for LoadingSkeleton (closes Goldii-locks#281)
…e_raise_modal Implement overlay wrappers on dispute_raise_modal to fit constraints on mobile device screen heights. Changes: - Added overlayWrapper class with flex layout and max-h-[92vh] for mobile height constraints - Added scrollableContent class to allow middle content to scroll independently - Updated panel structure to use overlay wrapper with header, scrollable content, and actions - Added flex-shrink-0 to header and actions to prevent shrinking - Added comprehensive test cases for mobile viewport validation
No textual conflict against current main -- GitHub's cached mergeability had gone stale (it reported DIRTY where a local three-way merge is clean), the same as on Goldii-locks#366. Merging main in here refreshes the head so CI runs against it. lint 0 errors / tsc 0 errors / 2035 tests passing / build OK
…e-modal-stories Feat: Implemented Storybook Interface for Dispute Raise ModaL
…he shared badge This branch predates the LoadingSkeleton rewrite (Goldii-locks#349/Goldii-locks#351/Goldii-locks#352/Goldii-locks#354) and the WalletBadge consolidation, and git merged it without conflicts into something that does not parse -- the classic silent damage: - LoadingSkeleton.tsx ended up as this branch's pre-token markup concatenated with main's current component, leaving an unterminated JSX block followed by `interface LoadingSkeletonProps`. - WalletBadge.tsx ended up with two complete implementations: two `formatAddress` declarations and two `export default`s. - Navbar.tsx and wallet_badge.test.tsx each got duplicate import lines. LoadingSkeleton and SignatureTimeoutAlert are incidental to this PR -- its subject is the wallet badge -- and the branch's own copies were already broken before the merge (its SignatureTimeoutAlert interleaves a useEffect into the existing useMemo, leaving two catch blocks and an undefined setParseMessage). Both were taken from main. The badge work itself is real and entirely additive: 16 of its 33 cases already passed against main's component, and the other 17 cover features main did not have. Those were added to main's derived-status rendering rather than replacing it: isValidStellarAddress exported; G + 55 base32 chars, format only error / fieldError wallet-field-error + wallet-error-text, aria-invalid, red status dot validateAddress flags a malformed address the same way alert wallet-alert-badge, amber dot; error wins empty placeholders wallet-badge-placeholder, -custom and wallet-empty-list-placeholder for empty accounts/wallets/items, plus data-empty-state One distinction worth noting: a present-but-blank address (`""`) is an empty state, while a missing one (`null`) stays the ordinary disconnected badge unless the caller passes placeholder copy. The branch's own tests require both readings. All four wallet-badge suites now pass together. lint 0 errors / tsc 0 errors / 2052 tests passing / build OK
The branch's lockfile is not valid JSON -- it fails to parse at offset 101100 in the branch itself, before any merge -- which is why CI died at "Install dependencies" with npm error code EUSAGE rather than at a lint or test step. The branch does not modify package.json at all, so its 5002-line lockfile change had nothing to express; main's lockfile is the correct one for these dependencies. Verified with a clean npm ci against the merged package.json. lint 0 errors / tsc 0 errors / 2052 tests passing / build OK
…ole-errors-and-transaction-tracking-in-network-sync-checker # Conflicts: # __tests__/freighter_connector.component.test.tsx # __tests__/freighter_multisig_hook.test.ts # __tests__/signature_timeout_alert.test.tsx # __tests__/signature_timeout_alert_timeout.test.ts # app/components/SignatureTimeoutAlert.tsx # vitest.setup.ts
…pty-placeholder feat(wallet): render descriptive placeholders for empty data states in wallet_badge
…lready carries This branch and its three siblings (Goldii-locks#359/Goldii-locks#360/Goldii-locks#361) share a base of commits that rework the same four test files and SignatureTimeoutAlert, so most of the conflict here is the same work expressed twice: - signature_timeout_alert_timeout.test.ts: `onRejected` vs main's `settled` for the same catch-before-advance handle. - freighter_multisig_hook.test.ts: an equivalent signed-envelope builder to main's `buildSignedEnvelopeXdr`. - signature_timeout_alert.test.tsx: the same act() calls, reformatted. - freighter_connector.component.test.tsx: a different mocking strategy for the same cases. None of those four adds a test case -- the it() counts are identical to this branch's own merge base -- so main's versions were kept and this branch's rewrites dropped. SignatureTimeoutAlert took the branch's explanatory comment, which describes what main already does. vitest.setup.ts combines both: the branch's guard is the better one (it also catches the experimental Node localStorage global that reads as undefined and shadows jsdom's), while main's defined the property on both globalThis and window. The merged version does both. The branch's actual deliverable is untouched: NetworkSyncChecker.tsx and its 300-line component suite. lint 0 errors / tsc 0 errors / 2061 tests passing / build OK
…ct-testing-library-assertions-for-network-sync-checker [162] Write React Testing Library assertions for network_sync_checker
…eractive-states-for-notification-bell # Conflicts: # __tests__/freighter_connector.component.test.tsx # __tests__/freighter_multisig_hook.test.ts # __tests__/signature_timeout_alert.test.tsx # __tests__/signature_timeout_alert_timeout.test.ts # app/components/SignatureTimeoutAlert.tsx # app/components/notification_bell.tsx # vitest.setup.ts
Only vitest.setup.ts conflicted, and main already carries the combined version resolved on Goldii-locks#358 -- which includes this branch's own guard for the experimental Node localStorage global. Took main's. The branch's deliverable lands unchanged: the network_sync_checker logging rework and its 197-line suite. lint 0 errors / tsc 0 errors / 2072 tests passing / build OK
…y-list-views-for-notification-bell # Conflicts: # __tests__/freighter_connector.component.test.tsx # __tests__/freighter_multisig_hook.test.ts # __tests__/signature_timeout_alert.test.tsx # __tests__/signature_timeout_alert_timeout.test.ts # app/components/notification_bell.tsx # vitest.setup.ts
…nsole-errors-and-transaction-tracking-in-network-sync-checker [161] Format console errors and transaction tracking in network_sync_checker
…nteractive-states-for-notification-bell [321] Add premium interactive states to notification_bell
…pty-list-views-for-notification-bell [323] Design empty list display views for notification_bell
…e modal The branch predates Goldii-locks#375's rewrite of DisputeRaiseModal, and its own edit to that file is broken independently of the merge: it deletes the counterparty <dd>'s closing tags and splices a stray label/textarea fragment in their place, so the branch does not parse. The merge inherited that. The lib half is sound and is the real contribution, so it was kept and the component rebuilt around it: the panel becomes a plain flex column, DISPUTE_MODAL_CLASSES.overlayWrapper takes the padding and the height cap, and a scrollableContent region wraps everything between the header and the actions -- so on a short viewport the middle scrolls while the title and buttons stay pinned. Two assertions in the responsive suite described the old arrangement and now follow it: the p-4/sm:p-6/lg:p-8 checks moved from the panel to the wrapper, and the panel's overflow-y-auto check became a query for the scrollable region inside it. The branch's own "keeps action buttons clickable" case also assumed the confirm button is live with an empty reason, which Goldii-locks#375 changed -- it now fills the field first, which is what a user reaching those buttons would have done anyway. lint 0 errors / tsc 0 errors / 2098 tests passing / build OK
…spute-modal-mobile-overlay-wrappers Goldii-locks#336 Handle mobile viewports navigation styling in dispute_raise_modal
Two Navbar conflicts: this branch swaps the inline provider select and Connect button for a <WalletSelectorModal>. That is incidental to the PR -- its subject is TransactionSignerPanel (Goldii-locks#222) and none of its tests touch the Navbar -- and main's navbar-wallet-kit suite queries the select by label and the button by name, so main's Navbar was kept. TransactionSignerPanel then failed lint: it parsed the XDR in a mount effect and wrote the result to three pieces of state, which react-hooks/set-state-in-effect flags as cascading renders. Parsing is a pure function of the XDR and the wallet/network in play, so it now derives during render through useMemo. The signing lifecycle is still real state (idle -> signing -> success/error), so it stays in useState as `signingState`, with a parse failure outranking it: const state = parseErrorMessage ? "parse-error" : signingState; Rendering is unchanged -- `state`, `structure` and `parseErrorMessage` mean exactly what they did before. lint 0 errors / tsc 0 errors / 2140 tests passing / build OK
…on-signer-panel Feat(wallet): build TransactionSignerPanel component (Goldii-locks#222)
The rabe_connector conflict was structural, not semantic: this branch's addition is a single append-only hunk at the end of the file (156 lines, zero deletions), but main has grown past that point, so git aligned the two additions and split an existing function in half. Rebuilt as main's file plus the branch's block appended -- the persistent address cache lands whole. Running the suite then exposed a real defect in dashboard-accessibility.test.tsx (from Goldii-locks#306): five waitFor calls that are never awaited. Three are nested inside an outer waitFor, so the click replays on every retry and the inner assertions never gate the test; one of them leaked a rejection that made vitest exit 1 while reporting all tests passed. Two more sit in synchronous tests, where nothing inside them ever ran. With the assertions actually running, two failed for a second reason: the dashboard auto-expands the first job once the fetch resolves, so an unconditional click closed the very panel they were looking for. They now click only while the row is still collapsed, and go through fireEvent so React flushes the update inside act(). lint 0 errors / tsc 0 errors / 2173 tests passing / build OK, exit 0
|
@emmyokolo2525-cyber Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements secure persistent caching for active wallet addresses in
rabe_connector, as described in issue #137. Active addresses are now serialized tolocalStorageand correctly restored across page reload cycles.Changes
app/lib/rabe_connector.tsNew exports added:
RABE_CACHE_KEYlocalStoragekey for the cache entryRabeActiveAddressCacheversion,address,savedAt,networkvalidateRabeAddressCacheserializeRabeAddressCachedeserializeRabeAddressCachenullon corrupt/invalid datasaveRabeAddressCachelocalStorage; SSR-safe; logs warning vialogRabeWarningon quota errorsloadRabeAddressCachelocalStorage; SSR-safe; returnsnullwhen absent or corruptclearRabeAddressCache__tests__/rabe_connector.test.ts33 new test cases across three describe blocks:
setItemthrowing, timestamp boundsVerification
tsc --noEmit→ 0 errorsloadcall)Closes #137