chore: use io-ts to parse safe keycard box + parts encoding in QR headers for multipart QRs#9225
chore: use io-ts to parse safe keycard box + parts encoding in QR headers for multipart QRs#9225s84krish wants to merge 1 commit into
Conversation
e4495b2 to
5cde131
Compare
|
Claude finished @s84krish's task —— View job Code Review Complete ✅Todo List:
Review SummaryThis PR successfully addresses the followups from the previous discussion and implements several improvements to vault keycard generation. The changes are well-structured and maintain backward compatibility while adding the new part-based QR encoding. ✅ Strengths1. io-ts Integration (
|
| * does not affect PDF-based recovery. | ||
| */ | ||
| function encodeQrCodePart(fragment: string, index: number, total: number): string { | ||
| return total > 1 ? `${index + 1}/${total}|${fragment}` : fragment; |
There was a problem hiding this comment.
Wondering what the best way to do this parts encoding would be - if it is even necessary.
There was a problem hiding this comment.
Pull request overview
This PR updates the key-card module’s vault keycard UX and data handling by (1) switching vault box parsing to io-ts validation, (2) updating vault-specific Box D wording/copy, and (3) introducing QR “part headers” for split vault QR payloads while refining the PDF layout around multipart QRs.
Changes:
- Add
io-ts-based decoding forparseVaultKeycardBox, and adjust unit tests accordingly. - Update vault keycard wording (Box D title/description and “vault password” language) and plumb vault/wallet entity wording through passcode QR generation.
- Add opt-in QR fragment part headers (enabled for vault keycards) and reposition multipart notes under the QR column with improved row-height calculation.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/key-card/test/unit/vaultQrData.ts | Updates vault QR data expectations (vault wording) and loosens malformed box parsing assertions; adds a “well-formed box” decode check. |
| modules/key-card/src/types.ts | Adds useQrPartHeaders option and clarifies page break behavior docs. |
| modules/key-card/src/parseKeycard.ts | Switches parseVaultKeycardBox to io-ts validation and updates Box D title matching to support vault wording. |
| modules/key-card/src/index.ts | Enables QR part headers for vault keycard generation. |
| modules/key-card/src/generateQrData.ts | Adds wallet/vault entity wording to Box D generation; updates vault box descriptions to “vault password”. |
| modules/key-card/src/drawKeycard.ts | Implements QR part headers (opt-in) and adjusts multipart QR layout/note placement and row-height calculations. |
| modules/key-card/package.json | Adds runtime deps needed for io-ts decoding (fp-ts, io-ts, io-ts-types). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
5cde131 to
f8dc5c4
Compare
pranishnepal
left a comment
There was a problem hiding this comment.
added my commentary - will defer to folks involve in the project for a thorough review
f8dc5c4 to
1bf1a2c
Compare
1bf1a2c to
4cacf1c
Compare
zahin-mohammad
left a comment
There was a problem hiding this comment.
Review
Verified locally: tsc --noEmit clean, 32/32 unit tests pass. Traced the layout math and QR-header logic by hand.
Blocking: still uses "vault" — we renamed the product to "safe"
The whole module still says vault in both customer-facing copy and the public API, and this PR compounds it (adds 'vault'/'Vault' copy paths). Needs a vault→safe pass:
- Customer-facing copy (highest priority — printed on the keycard):
generateQrData.ts—titleNoun = ... ? 'Vault' : 'Wallet'renders "D: Encrypted Vault Password"generateQrData.ts— "…encrypted with your vault password." (x2) + the'vault'literal passed togeneratePasscodeQrDataparseKeycard.ts— the'encrypted vault password'title matcher must change in lockstep with the rendered title, or PDF recovery of Box D breaks
- Public API (
generateVaultKeycard,generateVaultQrData,GenerateVaultQrDataParams,VaultKeycardRoots,VaultRootKeyType,VAULT_ROOT_ORDER,parseVaultKeycardBox,KeycardEntity: 'vault') plus internals (buildVaultBoxData, codecs) and thevaultQrData.tstest file.
Low-risk: these symbols have zero consumers elsewhere in BitGoJS and the feature is unreleased, so renaming breaks nothing. Note most of the "vault" naming came in the prior commit 15fdb259d5, so a complete rename spans both commits. Leave the faq.ts "bank vault or home safe" line alone — that's a real-world example, not the product term.
No other breaking changes
- Wallet keycard output is unchanged:
useQrPartHeadersdefaultsfalseandentityNoundefaults'wallet'. - New QR part-header format (
"<i>/<n>|<fragment>") has no existing consumer (reassembly is for a future recovery tool). - Changed
parseVaultKeycardBoxerror strings — grepped repo, no external matchers. drawOnePageOfQrCodessignature change is internal (not exported).
Correctness — looks sound
Traced the refactored rowHeight, including multi-part keys overflowing to a second page (continuation resets qrColumnBottom to the new page; when all QRs already fit page 1 the page-2 call returns endY == topY so height falls back to textHeight). Single/non-multipart path pins qrColumnHeight = qrSize, matching prior behavior.
Non-blocking notes
- Three new deps in a browser-bundled module (
fp-ts+io-ts+io-ts-types) replace a ~15-line dependency-free validator for a flat 4-key object. Intentional (io-ts is the repo standard, reviewer-requested) — flagging the bundle-weight trade-off. - Dep version drift:
fp-ts@^2.16.2/io-ts-types@^0.5.19vs^2.12.2/^0.5.16in abstract-utxo/lightning. Consider aligning. drawKeycard.tslayout changes are untested (~10% coverage) — verified only via the attached PDFs. This is the riskiest part of the diff; a regression would be silent. Consider a unit test for the multi-partrowHeight/note placement.- Header is added after splitting, so a QR fragment can slightly exceed
QRBinaryMaxLength(1500 → ~1505). Harmless, well under the 2953 cap.
|
Will update name from vault -> safe and then rebase. |
4cacf1c to
9648200
Compare
a6a9712 to
54bf80a
Compare
9648200 to
23e6a22
Compare
23e6a22 to
9648200
Compare
- parseSafeKeycardBox: validate via an io-ts codec (JsonFromString piped into the roots codec) instead of manual JSON.parse + type checks - encode split-key QR fragments with a "<index>/<total>|" part header, opt-in via useQrPartHeaders (safe keycard only; wallet output unchanged) Ticket: WCN-1193 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
9648200 to
0eac541
Compare
Ticket: WCN-1193
Description
This PR addresses followups from #9209 (comment). Also includes a new part-based encoding for the QRs. Mock below:
Copy and formatting updates have been folded into: #9242
Type of change
How Has This Been Tested?
Generated PDFs locally for vault and wallet keycards using mock data.
safe-keycard.pdf
wallet-keycard.pdf