diff --git a/agent-feedback/bugs.md b/agent-feedback/bugs.md index 1a1dde05..3a1f7356 100644 --- a/agent-feedback/bugs.md +++ b/agent-feedback/bugs.md @@ -289,3 +289,9 @@ The dev watcher's `all` listener only calls `invalidateVirtualFiles()` and re-em `packages/run/src/vite/codegen/index.ts` › `renderFetch` | 2026-08-21 | impact:high | effort:low `renderFetch` emits `catch (error) { if (import.meta.env.DEV) throw error; return new Response(null, { status: 500 }); }`, so in a production build the error object is discarded without ever being read. On the `app` starter with `src/routes/boom/+handler.ts` throwing `intentional-boom-marker-9271`, `PORT=… NODE_ENV=production node --enable-source-maps ./dist/index.mjs > server.log 2>&1` answers `GET /boom` with `500` and `content-length: 0`, and `server.log` is **0 bytes** after two such requests; the identical throw under `marko-run dev` prints `Request failed with error: …` plus a full stack from `createErrorMiddleware` (`packages/run/src/adapter/dev-server.ts`), and a post-flush throw in the same production server _does_ print a stack from `createMiddleware`'s catch — so this one branch is the only silent path, not a policy. Adding a `+500.marko` does not help an operator: an HTML request then renders the error page but still logs nothing, and an `Accept: application/json` request to the same route still returns a bodiless 500 with an empty log, so every API 500 is invisible. Log the error (and the method/URL, which even the post-flush stack lacks) from that catch before returning the 500, or give the generated router an `onError` seam adapters can hook — `console.error` here is the same call the middleware already makes one layer up, and the open entry "Write a 500 status instead of destroying the socket when the middleware has no `next`" assumes a `console.error` that this pre-flush path never reaches. + +## Accept the documented `(options, handler)`, `(options, handlers[])` and `(options)` forms in the pre-typegen `GlobalDefineHandler` fallback + +`packages/run/src/runtime/types.ts` › `GlobalDefineHandler` | 2026-08-28 | impact:med | effort:low + +`GlobalDefineHandler` is the type behind the global `Run` verb helpers for every route file the generated `.marko-run/routes.d.ts` does not yet cover (`GlobalNamespace` maps each verb to it, and `packages/run/src/runtime/index.ts` declares `var Run: GlobalNamespace`), and it declares only the `(handlers[])` and `(handler)` overloads while the per-file `DefineHandler` next to it declares five. So three of the five forms the docs list under `website/docs/marko-run/validation.md` › `## Verb Helpers` (`Run.POST(options, handler)`, `Run.POST(options, [auth, handler])`, `Run.POST(options)`) are compile errors until a `marko-run build`/`dev` regenerates route types: TS2554 "Expected 1 arguments, but got 2" plus TS7006 on `ctx`/`next` for the two-argument forms, TS2769 "No overload matches this call ... Overload 1 of 2 ... 'search' does not exist in type" for the options-only form. That window is not just the freshly added file: `.marko-run/` and `dist/` are gitignored, so a clean clone of a working app fails `mtc` the same way on its already-checked-in `src/routes/+handler.ts`, and the framework reads as calling its own documented API wrong. Declare the three missing signatures over the global `Context`, which is local to `runtime/types.ts` and needs nothing from the typegen and dev-watcher entries in `dx.md` that quote the same TS2554 symptom but attribute it to codegen timing; the test is a fixture asserting all five documented forms type-check with no `routes.d.ts` in the program. Keep the scope honest when fixing it: on one cold-cloned app this is 3 of 36 errors, the other 33 being the `data`/`$global.data` `unknown` cascade the "Degrade gracefully (or emit one clear diagnostic) when route types are missing during type-check" entry already covers. Check: in an app on `@marko/run` 0.11.12 with `@marko/type-check` 3.2.0 and tsconfig `include: ["src/**/*"]`, with a `routes.d.ts` present that does not cover a new route, `mkdir -p src/routes/probe && printf 'export const POST = Run.POST({ form: { maxBytes: 16_384 } }, async (ctx) => {\n return new Response("ok");\n});\n' > src/routes/probe/+handler.ts && rm -f dist/tsconfig.tsbuildinfo && npx mtc` exits 1 with `src/routes/probe/+handler.ts:1:62 - error TS2554 ... Expected 1 arguments, but got 2` and `1:69 - error TS7006 Parameter 'ctx' implicitly has an 'any' type`, while `npx marko-run build && rm -f dist/tsconfig.tsbuildinfo && npx mtc` exits 0 on byte-identical sources; the `rm -f dist/tsconfig.tsbuildinfo` is load-bearing, since a leftover `dist/tsconfig.tsbuildinfo` makes `mtc` exit 0 off cache and hides all of it. The other two forms in the same file reproduce it too: `export const GET = Run.GET({ search: (value) => ({ page: Number(value.page) || 0 }) });` gives TS2769 (`Overload 1 of 2 ... 'search' does not exist in type '(...)[] & readonly unknown[]'`) plus TS7006 on `value`, and `export const PUT = Run.PUT({ form: { maxBytes: 16_384 } }, [(ctx, next) => next()]);` gives TS2554 plus TS7006 on `ctx` and `next`.