src/http.ts reads every body against one cap and one deadline — BODY_MAX = 64 * 1024 and BODY_MS = 5_000 — and src/server.ts calls readForm/readText with the defaults. That is right for every form this shop has: a checkout is under a kilobyte and 5 seconds is generous on a bad phone connection (I checked: a trickled body is refused with 408, and an ordinary POST is unaffected). It is wrong for the first route that carries a file. #38 asks an admin to upload a product photograph; a photograph is 100 KB to 5 MB, so under today's numbers every upload is a 413, and a 2 MB upload on a slow uplink would be a 408 even if the cap were raised.
The functions already take max and ms as parameters — what is missing is a way for the route table to say so, and a default that does not change for anything else.
Done looks like
[ ] A route in src/routes.ts may declare its own bodyMax and bodyMs; a route that declares neither reads exactly as it does today, against BODY_MAX and BODY_MS.
[ ] src/server.ts passes the route's numbers to the one read it already does — no second read path, and the raw (webhook) branch is held to the same rule.
[ ] The declared numbers are bounded in code, not by whoever edits the table: a ceiling above which a route may not ask, so a typo cannot hand the process an unbounded read.
[ ] 413 and 408 still answer with the words they answer with now, and the counting is still of bytes actually read — never a believed Content-Length.
[ ] Tests: a route with a raised cap accepts a body the default would refuse; the same body on any other route is still 413; a slow body on the raised route is still refused at its own deadline; the default routes are unchanged.
[ ] AGENTS.md's line about the cap still describes the code — update it to say the cap is per route with a default.
Filessrc/routes.ts, src/server.ts, src/http.ts if the ceiling wants a home, src/server.test.ts or src/https.test.ts, AGENTS.md.
Risks This is the app's memory bound: a raised cap on the wrong route is how a process is filled up, so keep the ceiling low enough to be dull and the raise on one route only. Nothing here should touch the idle timeout in src/server.ts — the stream depends on it.
Suggested mason, with sentinel reading the pull; #38 waits for this.
src/http.tsreads every body against one cap and one deadline —BODY_MAX = 64 * 1024andBODY_MS = 5_000— andsrc/server.tscallsreadForm/readTextwith the defaults. That is right for every form this shop has: a checkout is under a kilobyte and 5 seconds is generous on a bad phone connection (I checked: a trickled body is refused with408, and an ordinary POST is unaffected). It is wrong for the first route that carries a file. #38 asks an admin to upload a product photograph; a photograph is 100 KB to 5 MB, so under today's numbers every upload is a413, and a 2 MB upload on a slow uplink would be a408even if the cap were raised.The functions already take
maxandmsas parameters — what is missing is a way for the route table to say so, and a default that does not change for anything else.Done looks like
src/routes.tsmay declare its ownbodyMaxandbodyMs; a route that declares neither reads exactly as it does today, againstBODY_MAXandBODY_MS.src/server.tspasses the route's numbers to the one read it already does — no second read path, and the raw (webhook) branch is held to the same rule.413and408still answer with the words they answer with now, and the counting is still of bytes actually read — never a believedContent-Length.413; a slow body on the raised route is still refused at its own deadline; the default routes are unchanged.AGENTS.md's line about the cap still describes the code — update it to say the cap is per route with a default.Files
src/routes.ts,src/server.ts,src/http.tsif the ceiling wants a home,src/server.test.tsorsrc/https.test.ts,AGENTS.md.Risks This is the app's memory bound: a raised cap on the wrong route is how a process is filled up, so keep the ceiling low enough to be dull and the raise on one route only. Nothing here should touch the idle timeout in
src/server.ts— the stream depends on it.Suggested mason, with sentinel reading the pull; #38 waits for this.