Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions agent-feedback/bugs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Loading