Repository navigation
fix(rest): a refused xlsx export answers the 400 envelope, not a 200 workbook stream - #27888
Conversation
…workbook stream The xlsx export opened its streaming workbook writer before the first read, which committed the response to a streaming 200, so a query the read refused (for example a search over a field the object does not have) reached the client as a 200 instead of the 400 envelope csv and json answer. Open the writer after the first page is read, before the zero-row break, mirroring the json fix. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4cyUucJoh7384vix5rh
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 19 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 9734ad831fc052fe43ae14eab497789d601feab1 && git checkout 9734ad831fc052fe43ae14eab497789d601feab1
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin da94c11337fdb4c37ee809e9748a76791a5199cc 733ab4dc94cfe89e33edc0615ddb8377b8ebe8a1 && git checkout -B drift-repro da94c11337fdb4c37ee809e9748a76791a5199cc && git merge --no-ff 733ab4dc94cfe89e33edc0615ddb8377b8ebe8a1
node scripts/docs-audit/affected-docs.mjs --json da94c11337fdb4c37ee809e9748a76791a5199cc |
|
domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL 维护者速读
席位意见:ACCEPT。 席位核对Head-sha:
|
Requested by Elon · project thread
domain:server#4 · os-elon-musk · session_016WV4cyUucJoh7384vix5rh
Fixes #27755
维护者速读
packages/rest/src/data-action-routes.ts导出循环里新增的createXlsxStream那一行。GET /api/v1/data/OBJECT/export?format=xlsx&search=x&searchFields=nope应回 400 INVALID_FIELD,与 csv 一致;不带错误参数的 xlsx 导出照常下载可打开的工作簿。What changes
packages/rest/src/data-action-routes.ts: the xlsx export opens its workbook writer (createXlsxStream) after the firstfindDataanswers, not before the read loop. The writer is opened inside the loop on the first chunk, placed before the zero-row break next to json's opening bracket (fix(rest): a refused json export answers the 400 envelope, not a truncated 200 stream #27753), so an empty export is still a readable workbook. Nothing else in the route changes, and the async import-job region (fix(rest)!: an async import job whose every row failed ends failed, not succeeded #27795) is untouched.packages/rest/src/export-xlsx-refusal-envelope.test.ts(new): pins both halves through the realHonoHttpServer..changeset/27755-xlsx-export-read-first.md: patch for@objectstack/rest.Why
Opening the exceljs streaming writer commits the Hono adapter to a streaming 200. Opening it before the first read meant a query that read refused reached the client as a 200 workbook download, while
format=csv(and, since #27753,format=json) answered the 400 envelope. Triage 6510461172: the xlsx writer opens after the first page is read and answers the same envelope. A refusal on a later page is not widened here.Verification
SqlDriver(SQLite):?search=x&searchFields=nope(400 INVALID_FIELD) and?search=x&searchFields=,(400 VALIDATION_ERROR) answer the same status and body forformat=xlsxas forformat=csv. Ablation: on the unfixed code both xlsx rows are red (expected 200 to be 400); with the fix, green.page=50, 120 rows) and zero rows answers 200, the workbook content type,X-Export-Styles: applied, the same number of reads, and a workbook that loads with the same cells (header + rows; empty for zero rows). Green on the unfixed code too, so the success path did not move.dispatch-gates --ran: 59 derived families, 58 run green, 1 NOT MEASURED (check:dual-build-cjs-loads, exit 3, needs a whole-tree build).pnpm lintgreen. After mergingmain(which brought fix(rest)!: an async import job whose every row failed ends failed, not succeeded #27795):@objectstack/resttsc --noEmitgreen and full suite green (353 files, 7027 passed, 350 skipped); the derived gate list is unchanged.Clause-②: no
Metadata-protocol: none
Human Minimum
packages/specholds no runtime logic.pnpm lintpasses.main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed. (not touched)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4cyUucJoh7384vix5rh