fix(export): route search-results ADIF export through the shared generator - #230
Merged
Merged
Conversation
…rator The /api/contacts/search?export=true path hand-rolled its own ADIF serializer instead of reusing generateAdif(). That copy carried three defects the main export had already shed: - Declared field lengths with JS String.length (UTF-16 code units) rather than the UTF-8 byte count ADIF requires — the interop bug fixed for the main export in #228. Accented names, ø-callsigns and CJK QTHs came out with wrong lengths and got truncated/mis-aligned by strict readers (LoTW/TQSL, Cloudlog, N1MM). - Called .toString()/.length on frequency/mode/band unconditionally, so a single contact imported without one of those fields 500'd the whole export. - Emitted only ~11 fields, silently dropping DXCC, QSL status, country, zones and station info. Delegating to generateAdif() fixes all three and keeps the two export paths in lockstep. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Owner
Author
|
Review (unable to submit formal approval — GitHub rejects self-review since this PR and I share the same authenticated account): Verified this correctly routes the search export through the shared
Verdict: Approve. No correctness, security, or convention issues found. |
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.
Problem
The search page's Export button (
/api/contacts/search?export=true) hand-rolled its own ADIF serializer rather than reusing the sharedgenerateAdif()insrc/lib/adif.ts. That duplicated copy had drifted and carried three defects the main per-station export had already fixed:String.length(UTF-16 code units) instead of the UTF-8 byte count ADIF requires — the exact interop bug fixed for the main export in fix(adif): declare export field lengths as UTF-8 byte count #228. A name likeJosé, anø-callsign, or a CJK QTH exported with the wrong declared length and got truncated/mis-aligned by strict readers (LoTW/TQSL, Cloudlog, N1MM)..toString()/.lengthonfrequency,modeandbandunconditionally. A single contact imported without one of those (all nullable columns) crashed the entire export with a 500.qsl_rcvd/lotw_qsl_rcvd/…), country, zones, and station info that the main export includes — so a search export was far less useful for awards/QSL tooling.Solution
Route the export branch through the existing, well-tested
generateAdif().SELECT *fromcontactsalready returns snake_case columns matchingAdifExportContact, so the rows feed straight in. Station ("my_*") fields are absent when a search spans multiple stations;adifField()skips nullish values, so they're simply omitted rather than mis-declared. Content-Type is aligned toapplication/octet-streamto match the main export. This removes ~45 lines of duplicated serialization and keeps both export paths in lockstep going forward.The frontend consumer (
src/app/search/page.tsx) just downloads the returned blob, so the change is transparent to it.Testing
generateAdifregression tests intests/adif-generate.spec.ts:frequency/mode/bandwithout throwing (the old crash),npm run typecheck— cleannpm run lint— cleannpm run build— succeedsnpx playwright test tests/adif-generate.spec.ts— 10/10 passFollow-up
gridLocator,startDate,endDate,qslStatus) are still camelCase, a known drift noted in CLAUDE.md; left untouched here to keep this change focused.🤖 Generated with Claude Code