Skip to content

fix(routes): bind registrations to consumer generations - #17

Open
Upd4ting wants to merge 5 commits into
fix/observable-registered-routesfrom
feat/bind-route-callback-context
Open

fix(routes): bind registrations to consumer generations#17
Upd4ting wants to merge 5 commits into
fix/observable-registered-routesfrom
feat/bind-route-callback-context

Conversation

@Upd4ting

@Upd4ting Upd4ting commented Aug 21, 2026

Copy link
Copy Markdown
Member

Summary

  • explicitly revert the two callback-wrapper commits previously proposed on this branch
  • bind API route decorators and registration APIs only during cold module evaluation through the resolver facade
  • preserve every original HTTP callback, parameter provider, modifier, handler object field, class, and metadata identity
  • track route ownership by lifecycle generation so HMR removes stale routes without touching a replacement
  • expose UnregisterRoute for lifetimes shorter than a module
  • keep internal.routesProxy as a non-enumerable alias of the canonical root proxy instead of a duplicate declaration
  • require the interface-core release that provides /facades

Why

The previous implementation restored consumer context every time API invoked a route callback or computed parameter. It fixed provider selection, but added an unacceptable steady-state HTTP cost.

The resolver now gives each consumer a generation-specific interface facade. API uses that cold context while decorators call RegisterRoute; the registered callback and computed providers are not wrapped. Derived Auth providers already close over their selected Auth facade, so execution later under API no longer loses provider selection.

Identity and lifecycle guarantees

  • route callback after registration is === the controller method
  • parameter providers and modifiers are unchanged
  • observer PR feat(routes): add registered route lifecycle observer #16 remains observer-only and is still this PR's base
  • stale route entries are removed by exact generation owner
  • the legacy internal.routesProxy and root routesProxy are the same object

Validation

  • pnpm lint
  • pnpm build
  • complete API module suite through candidate Core and the real API provider: 94 passing
  • route lifecycle/facade tests cover unchanged callback identity, selected providers, explicit removal, HMR overlap, replay, observer ordering, and cleanup
  • Core real Auth/API two-consumer integration passing
  • git diff --check

Performance

The rejected callback-wrapper design measured approximately -8% to -14% throughput in the final three-way benchmark. The resolver/cold-facade design has no request wrapper.

The isolated A/B gate (Node 24.19.0, pinned server CPU, 8 repetitions, 8-second samples) measured +1.15% JSON c100, +2.46% dynamic routes, +1.68% POST echo, and -0.36% on the last of 1,000 routes. Registered HTTP callbacks are also strict-equal, providing a structural check that no per-request wrapper remains.

Release ordering

Merge #16 first. Release interface-core and Core before publishing this interface-api candidate. No merge or publication is performed by this PR update.

@Upd4ting Upd4ting changed the title fix(routes): preserve consumer execution context fix(routes): bind registrations to consumer generations Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants