Repository navigation
perf(proxy): raw passthrough on plain routes, shared PUT path, bounded rate limiter - #6
Merged
Merged
Conversation
…ound the rate limiter Plain forwarding routes now use the SDK forwardHttpRaw: request and response bodies are forwarded as Buffers without JSON.parse/stringify, and the upstream timeout covers the body. Routes that validate input stay in JSON mode; the admin target route keeps parsing its own body. The hand-written PUT fetch path is gone. The rate limiter sweeps expired buckets at most once per window and otherwise drops the oldest bucket in O(1) instead of scanning the whole map on every request.
Sebas1705
force-pushed
the
perf/phase2-raw-proxy
branch
from
November 12, 2026 17:53
56ec2ad to
66ec41a
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Depends on
AxiomNode/shared-sdk-client#3 (adds
forwardHttpRawand the@axiomnode/shared-sdk-client/proxy-rawexport). This PR cannot build until that PR is merged, because CI checks outshared-sdk-clientmain. The dependency declaration is unchanged (file:../../shared-sdk-client/typescript, lockfile untouched), exactly as the repo resolves the SDK today.What changes
src/app/routes/proxy.ts).forwardRequestnow usesforwardHttpRawby default: the request body goes upstream as the original bytes with the original content-type, and the upstream body comes back as a Buffer and is sent as-is (status and content-type preserved; as before, no other upstream headers are copied to the client). The upstream timeout now also covers reading the body.application/jsonbodies reach handlers as the original Buffer via a parser registered inproxyRoutes. A route that readsrequest.bodyitself opts back in withconfig: { parseJsonBody: true }(onlyPUT /internal/admin/ai-engine/target), using Fastify's default JSON parser, so its 400s are unchanged.GET /v1/mobile/games/quiz/random,GET /v1/mobile/games/wordpass/random,GET /v1/backoffice/users/leaderboard. The three ai-engine routes that only striplanguagefrom the query still go raw (body untouched). Tell me if you want the random routes raw as well: they are the largest responses, and the query validation does not depend on the response body.fetchbranch is deleted; PUT goes through the same shared helper (SDKForwardMethodnow includesPUT).rateLimiter.ts): no more O(n) scan per request when the map is full. Expired buckets are swept at most once per window; if still overRATE_LIMIT_MAX_TRACKED_KEYS, the oldest-inserted buckets are dropped in O(1) (reset keys are re-inserted so the front of the Map is the oldest window). The map is now actually bounded under an IP spray (previously it grew without limit once everything was fresh). For normal traffic limits behave the same.Client-visible differences (edge cases)
{}(the one existing test that pinned this was updated). An empty JSON body is still answered as{}.text/plainrequest body is now forwarded as sent with its own content-type (before: JSON-quoted string with a JSON content-type).Overlap with open PRs / not done here
TRUST_PROXY):trustProxyis covered there (TRUST_PROXYparsed inconfig.tsand applied inserver.ts), so it is intentionally not duplicated here. Fail closed on missing auth tokens, enforce routing allowlist, add trust proxy #3 also editsroutes/proxy.ts(internal-token checks on/internal/ai-engine/*routes and the admin allowlist), so expect a textual conflict in that file whichever merges second; it is mechanical (this PR touchesforwardRequest, the imports, the admin PUT route options and three call sites).upstreamCache(bounded + hashed key) is not in this repo: it lives inbff-backoffice(backoffice.ts), so it belongs to a bff-backoffice PR.Verification
Node 22, in
src/:npm run buildOK,npm run lintOK,npx vitest run130/130 passing (17 files), against the SDK branch of shared-sdk-client#3 linked locally. New tests (proxyRaw.test.ts, real HTTP upstream, no fetch mocks): byte-identical request and response bodies, content-type and status preserved, error statuses, empty/204/text responses, PUT via the shared path, no body when none sent, malformed JSON left to upstream, 415 for unknown types, 504 on a stalled body, JSON-mode routes still validate, admin target still parses JSON. Rate limiter: cap under an IP spray, sweep at most once per window, expired buckets still removed, limits still enforced.Not verified: CI (blocked until the SDK PR is merged), a run against real BFFs, and any load/CPU benchmark (the expected gain is an estimate from the review, not measured).