refactor(connect): extract the leaf concerns from CantonConnectProvider - #71
Draft
fernandomg wants to merge 19 commits into
Draft
refactor(connect): extract the leaf concerns from CantonConnectProvider#71fernandomg wants to merge 19 commits into
fernandomg wants to merge 19 commits into
Conversation
- every symbol the barrel exports carries a block: the six hooks and their result types, CantonConnectConfig and each field, Party, ConnectionStatus, the provider and its context value, the mock adapter, and the ./testing factories - each hook names its wagmi counterpart — useParty maps to useAccount, useExecute to useWriteContract plus useWaitForTransactionReceipt — and says where the shapes diverge: wagmi's hooks are TanStack Query mutations, ours resolve plain promises - satisfies the root CLAUDE.md rule that barrel exports carry JSDoc, and is the input issue #16 consumes for llms.txt and a docs site - comments only: no behaviour, no signature, no export changed
- drop the wrapper blocks on result and options interfaces (`Return value of useX`, `Options for …`) - drop property blocks that repeat the name and type; keep only defaults, gates and throws - compress every surviving block to one or two lines - 45 blocks kept of 61; 174 comment lines removed, 56 added Per review feedback on #48.
- applies to the four blocks added in 1d0a258 only - the em dashes elsewhere in the package predate this branch
The SDK returns one record per account, each carrying its own required status. Both doubles now model that per-account rather than wallet-wide: the fake wallet passes a declared status straight through, and the mock defaults to allocated when an account declares none.
- only `allocated` parties are offered: `initialized` never finished signing, `removed` is gone - an account reporting no status is kept, so older wallets and test doubles still work - `disabled` is never filtered on — such a party signs through the participant and still works - the primary account leads; the rest keep the wallet's order
- provider tracks parties beside party; one applyAccounts callback maps both - initial listAccounts read and the accountsChanged push share that mapping - parties empties wherever party goes undefined: lock, disconnect, dead probe - party is always parties[0]; a test states the invariant
- overlapping connect() calls each stored a teardown closure; the second overwrote the first - the orphaned wiring survived disconnect() and kept applying wallet pushes (#57) - guard with an attempt ref ahead of setStatus('connecting') and the listener teardown - non-async guard: an async wrapper would re-wrap the shared promise per caller, rejecting unhandled - keep one handler on the shared attempt so a fire-and-forget joiner cannot reject unhandled - document the idempotent-while-in-flight contract on the context value and useConnect
…nnected state - add a rejection handler to the mount init chain: connectError + disconnected, cancelled-aware - syncFromStatus claims connected only after the account read completes - a failed read tears down wiring, clears party/parties, surfaces the error, lands disconnected - syncFromStatus never throws, so connect()'s failure path keeps its original error - locked restore keeps its shape: no accounts to read, connected + isLocked directly - extract the repeated transitions into named helpers instead of setter piles
… failed connects - resetToDisconnected sets connectError unconditionally, so disconnect() clears a stale error - tear down wiring in runConnect's no-session branch: no live listeners on a disconnected provider - record the original error after recovery, so connectError matches what connect() rejects with
- walletSelection: 'in-page' hands the wallet choice to the dApp's own UI - the provider keeps the picker's resolve/reject pair and publishes the offered entries - useWalletPicker() exposes isOpen/wallets/select/cancel; select answers the SDK - an explicit walletPicker still wins over the mode; the default popup path is untouched - select with an unoffered id rejects the attempt with a plain Error naming the id - ConnectedWallet type defined for the wallet-identity task that follows
…d connect attempt - record why a pending choice was cancelled: user, disconnect, or unmount - connect()'s failure path recovers only after a user cancel; disconnect and unmount just re-throw - disconnect() cancels the choice, waits for the in-flight attempt to settle, then resets - a choice arriving while disconnect or unmount kills the attempt rejects instead of pending - unmount cancels the pending choice, so the attempt settles without unhandled rejections - fold the init-failure path onto resetToDisconnected(err)
- new connectedWallet.ts: the record under canton-connect:connected-wallet - written only when an attempt lands: connect success or the probe ending connected-and-locked - restored sessions read the record; a probe finding no session deletes it, as does disconnect() - a supplied walletPicker is wrapped only to note its result; the wrapper identity stays stable - corrupt or partial records read as absent, never throw - useParty() gains wallet (wagmi: useAccount().connector); popup mode reports none by design
- an inline walletPicker or additionalAdapters rebuilds the SDK per re-render (kept, documented) - a replacement instance whose restore probe finds nothing now resets status and party too - replacement keys on instance identity, so a StrictMode re-run never resets a first mount - an idle provider stays idle across swaps: only non-idle state is stale enough to clear - pin in-page mode: rerenders keep one SDK instance and a single init() - tests: dispose each fake wallet when its role ends, so a failing assertion leaks no listeners
- delete comments that restate the identifier below them: file headers, toParty, toParties - shorten every survivor running past ~100 characters - remove a stray /** that doubled the walletPicker JSDoc opener
…seam - add useParties, useWalletPicker, and walletSelection to the README tables - render connectError outside the isConnected branch in the quickstart - state that a rejected wallet is indistinguishable from a locked one from outside the SDK - note that an inline walletPicker or additionalAdapters rebuilds the SDK every render - state the two limits: wallet list only during an attempt, no wallet identity in popup mode - architecture: the themed picker is issue #50; describe the in-page context seam
…g state - a wallet window closed without answering leaves the connect RPC pending forever; disconnect() awaited that attempt and deadlocked before any reset. The kill is now recorded on the attempt itself and a condemnation race settles the caller, so disconnect cleans up immediately (found by hand in the harness with a real extension wallet, task 12) - the same fences close what the review pass then found: an in-page choice arriving after disconnect no longer opens over the clean slate (the picker fails closed and each choice dooms its own attempt); the cancel-recovery probe re-checks its fate after every await instead of only at catch entry; a mount restore resolving mid-attempt yields instead of wiring beneath it - guards runConnect's success path too, so a late wallet answer writes no state and never evicts a newer attempt - also braces the single-line guards and trues up the JSDoc the rework left stale
- the config identity note claimed additionalAdapters churn rebuilds the SDK; only walletPicker does, a new adapters array re-runs init() on the instance - the mount bullet now carries the replacement-instance rule from 51c096a - useConnect's disconnect JSDoc says it settles an unanswered connect
- buildAdditionalAdapters and AdapterConfig move to src/adapters.ts; AdapterConfig stays module-internal, nothing else needed it - TxStatusSnapshot and CantonConnectContextValue move to src/types.ts beside the config types; index.ts and useExecute import them from there directly, so the package surface is unchanged and no re-export shim is needed - the race core stays in CantonConnectProvider.tsx per canton-connect/CLAUDE.md - no behavior change: all 85 tests pass textually unchanged
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
5 tasks
fernandomg
force-pushed
the
feat/51-discovered-wallets-and-parties
branch
2 times, most recently
from
August 3, 2026 13:05
f05a67b to
c3f7c30
Compare
gabitoesmiapodo
force-pushed
the
feat/51-discovered-wallets-and-parties
branch
from
August 3, 2026 16:34
c3f7c30 to
f293a46
Compare
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
Closes #70
Pure code motion out of
CantonConnectProvider.tsx, sized by #63's pre-undraft review pass: thetwo leaf concerns with little or no shared state get their own modules; the race core stays put.
The provider goes from 671 to 596 lines with zero behavior change.
Draft until the #47…#63 train merges; GitHub retargets this PR automatically when #63's branch is
deleted on merge.
Changes
buildAdditionalAdaptersandAdapterConfigmove tosrc/adapters.ts;AdapterConfigstaysmodule-internal, nothing else needed it.
TxStatusSnapshotandCantonConnectContextValuemove tosrc/types.ts, beside the configtypes they reference;
index.tsanduseExecute.tsimport them from there directly.Acceptance criteria
From #70:
buildAdditionalAdaptersandAdapterConfigmove tosrc/adapters.tsTxStatusSnapshotandCantonConnectContextValuemove tosrc/types.ts. Diverged on themechanics: no re-export shim from
CantonConnectProvider— the only importers were our ownindex.tsanduseExecute.ts, repointed directly, so the package surface is identical withone source of truth.
boundary needs six crossings (
inPagePicker,offeredWallets,select,cancel,cancelPending, plus a pending-choice probe forcancelAttempt's condemnation message),which buys ~90 moved lines at the cost of a chattier seam than the file length ever was.
Recorded so the next reader doesn't re-litigate.
connect,runConnect,syncFromStatus, the mount effect,disconnect)stays in
CantonConnectProvider.tsx, percanton-connect/CLAUDE.mdpnpm -C canton-connect testpasses with no test edits; no public API changeTest plan
Automated tests
No new tests: pure code motion, and the proof is the existing suite passing textually unchanged —
85 tests, plus tsc, biome, knip, and the tsdown build, all green. Root gate re-runs before this
leaves draft.
Manual verification
No manual steps required.
Breaking changes
None. The package exports the same names from the same entries.
Checklist
Screenshots
None.