I also don't think every other framework has the exact same issues. Take a look at SvelteKit for example.
You can add data from the middleware/hook into a locals object (https://svelte.dev/docs/kit/hooks#Server-hooks-locals). This is request scoped and accessible from the route handlers when needed. It also supports type definitions (https://svelte.dev/docs/kit/types#Locals). I wouldn't call this brittle. It's just dependency injection.
Note that it doesn't explicitly support multiple middlewares either (well, sort of; there's https://svelte.dev/docs/kit/faq#How-do-I-use-middleware but I think you're meant to be using hooks for your code https://svelte.dev/docs/kit/hooks#Server-hooks-handle), but at least it's easy to use and doesn't intentionally try to obfuscate information from you.
Edit: It seems that at some point sequence (https://svelte.dev/docs/kit/@sveltejs-kit-hooks#sequence) got added, so disregard the paragraph above.
I haven't kept up with Next.js idioms but in generat that's what middleware is for. It's implied in the name. Middleware-chaining is a common idiom.
It's the littke details that Next.js middleware intercommunicate over HTTP headers (?!) that makes it a different pattern.
Dotnet has no problem with that when using Minimal APIs.
With that said, I do agree that nextjs middleware is trash. My main issue with it is that I never use nextjs on vercel, always on node, but I'm still limited in what I can use in middleware because they're supposed to be edge-safe. Eye roll. They are apparently remedying this, but this sort of thing is typical for next.