9Router: evaluate an AI gateway without assuming unlimited access
9Router architecture: separate request wrapping from model routing
Trace the inspected HTTP wrapper and distinguish its responsibilities from downstream provider selection and protocol conversion.
What you will learn
- The wrapper runs before Next handling
- Peer identity crosses a proxy boundary
- Background refresh is separately initialized
Before you start
- Basic command-line and configuration reading
- Ability to work in a disposable authorized environment
Design an evidence record that separates requested model, actual attempts and accepted response without retaining secrets.
Key takeaways
- The wrapper does not explain the whole router.
- Loopback is an explicit trust condition.
- Starting refresh is not proof of refreshed credentials.
The wrapper runs before Next handling
custom-server.js wraps http.createServer and places a handler before the application handler. It reads the TCP peer and selected forwarding headers, removes several client-supplied internal headers, and stamps derived request metadata.
This code is a request-boundary layer, not the full provider router. The README describes format translation, fallback and compression elsewhere in the application. We do not infer their exact order from a high-level diagram.
Peer identity crosses a proxy boundary
The wrapper trusts x-real-ip or the first x-forwarded-for value only when the TCP peer is one of its loopback forms. Otherwise it uses the socket address. A local reverse proxy therefore becomes responsible for supplying clean forwarding information.
A proxy in another container may not appear as loopback. Verify the actual socket address in the deployment instead of assuming every internal proxy matches this branch. Client identity affects downstream diagnostics and potentially rate-limiting behavior.
Background refresh is separately initialized
On listening, the wrapper attempts to import the background token-refresh module and start it. The source comments explain that standalone layouts without the source module can rely on application bootstrap. Import success and provider refresh success are still different observations.
Track request admission, chosen route and upstream outcome separately. This series inspects the wrapper and package scripts, not every provider executor, database path or credential-refresh implementation.
Decision guide
| Criterion | Option A | Option B |
|---|---|---|
| Best when | You need predictable behavior and easy auditing | You need adaptive optimization and have reliable telemetry |
| Main risk | May leave performance on the table | Can become difficult to explain or debug |
Implementation steps
- 1
Follow the wrapper before the application handler.
- 2
Identify the actual proxy TCP peer.
- 3
Keep routing and refresh outcomes separate from startup.
Copy-ready example
TCP request → custom wrapper → Next handler
wrapper: peer + trusted local forwarding → internal metadata
application → provider route → upstream resultFrequently asked questions
Does every internal proxy count as loopback?
No. Check the actual peer address and the implemented comparisons.
Have all fallback internals been verified here?
No. Their high-level purpose comes from the README; this source chapter covers the request wrapper.
Sources
- 9Router / custom-server.jsSource checked 2026-09-18
- 9Router / package.jsonSource checked 2026-09-18
- 9Router / README.mdSource checked 2026-09-18