feat(drafts): save proposals to the server-side SIWE drafts API - #107
Open
douglance wants to merge 1 commit into
Open
feat(drafts): save proposals to the server-side SIWE drafts API#107douglance wants to merge 1 commit into
douglance wants to merge 1 commit into
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
fionnachan
force-pushed
the
siwe/drafts
branch
from
August 20, 2026 16:55
4448888 to
cfb5673
Compare
Adds server-backed drafts alongside the existing localStorage autosave rather than replacing it. The two answer different needs: autosave is crash recovery for anyone with a wallet connected, this is a named copy tied to a SIWE session. Swapping the backend would have gated a currently-open flow behind sign-in and cost anonymous users their recovery, so all five localStorage call sites are untouched. CreateProposalForm gains two optional props and no new hooks. The session, the query client, and the router all live in ProposalDraftLoader, which reads `?draft=` and mounts the form on that draft's contents. Keeping SIWE out of the form is what lets its existing tests keep rendering it with only wagmi mocked. lib/drafts/mapping.ts encodes the three ways the two models disagree — governor naming, the title the form does not have, and the API's stricter action validation. That last one matters: the form's initial state is one blank action row, which requireAddress rejects, so posting it verbatim would always 400. Blank rows are dropped and anything still invalid is reported before the request rather than as a server error. Subject-scoped query keys now take `string | null | undefined`, matching `safes`, and the hooks gate on skipToken instead of `enabled`. That narrows the subject inside the queryFn closure, so no cast or placeholder "anon" subject is needed anywhere. Verified: lint clean, tsc clean, 1250 unit tests, production build still prerenders /proposal/new as static.
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.
Adds server-backed drafts alongside the existing localStorage autosave rather than replacing it.
The two answer different needs: autosave is crash recovery for anyone with a wallet connected, this is a named copy tied to a SIWE session. Swapping the backend would have gated a currently-open flow behind sign-in and cost anonymous users their recovery, so all five localStorage call sites are untouched.
Why the form takes props instead of calling the hooks
CreateProposalFormgains two optional props and no new hooks. The session, query client, and router all live inProposalDraftLoader. Its existing tests render it with only wagmi mocked — pulling SIWE inside would have forced aQueryClientProviderand a router into them permanently.The mapping module
lib/drafts/mapping.tsencodes the three ways the two models disagree: governor naming, the title the form doesn't have, and the API's stricter action validation. That last one matters — the form's initial state is one blank action row, whichrequireAddressrejects, so posting it verbatim would always 400. Blank rows are dropped and anything still invalid is reported before the request.Query keys
Subject-scoped keys now take
string | null | undefined, matchingsafes, and the hooks gate onskipTokeninstead ofenabled. That narrows the subject inside thequeryFnclosure, so no cast or placeholder"anon"subject is needed.Verified: lint clean, tsc clean, 1250 unit tests, production build still prerenders
/proposal/newas static.