ReviewOS

stacks/stx

feat(router): execute pure mode:'client' route middleware in the browser (client-side middleware registry + router-script wiring)

#1892
Closed glennmichael123 opened this 14 days ago · 1 comment
14 days ago

Split out of #1849, which is otherwise resolved. This is the one residual: defineMiddleware(handler, { mode: 'client' }) is still never executed in the browser.

Why it is not just wiring

The SPA router (packages/router/src/client.ts) is a stringified runtime — getRouterScript() returns a template literal that is injected as a <script>. It cannot import { runMiddleware }. The middleware registry (packages/router/src/middleware.ts) is a server-side Map populated when middleware definitions evaluate in Node (SSG / dev server). Neither the registry nor runMiddleware is exposed to the browser (grep -rn 'getMiddlewareNames\|runMiddleware\|middlewareRegistry' client.ts signals.ts → nothing).

So executing client-mode middleware needs new infrastructure, not a call site:

  1. Ship mode: 'client' middleware definitions to the browser (bundle them; the definitions currently only run server-side).
  2. Expose a client-side registry + runMiddleware to the router script (e.g. on window.stx), populated by those definitions.
  3. Call it from the SPA navigation path in the router script, honoring redirect / abort — mirroring the existing server path in dev-server/serve-app.ts:705 and the redirect-honoring already added in fe50af9036.

Scope note: run only mode: 'client' here. universal middleware already runs server-side on the SPA fragment fetch, so running it client-side too would double-execute side effects.

Why it can wait

The practical need #1849 was filed for — redirect unauthenticated users on SPA navigation — is already met by server/universal middleware (serve-app.ts runs it, client.ts honors the 302). Pure client-mode is only needed for a guard that must decide in the browser with no round-trip (e.g. off client-only state). Lower value, higher cost; hence its own issue.

14 days ago

Duplicate of #1891, which predates this and is better scoped — it pairs the client-mode question with the fail-open guard bug (both deliberately deferred from #1849 as published-package behaviour changes), and it makes the stronger call: don't implement client-mode execution. A guard that runs in the browser is not a security boundary, so shipping it would replace an API that visibly does nothing with one that looks like enforcement — a worse failure. I filed this without finding #1891 first. Closing in its favour.

Sign in to comment on this issue.