refactor(request): split fetch-helpers along its natural seams - #524
Conversation
Splits lib/request/fetch-helpers.ts (1,497 lines) into four focused modules, moving code verbatim: - token-refresh.ts (147 lines): shouldRefreshToken, refreshAndUpdateToken, plus private CodexAuthSetter, isRetryableRefreshFailure, isRetryableAuthSetterError - error-classification.ts (366 lines): isEntitlementError, isWorkspaceDisabledError, createEntitlementErrorResponse, the unsupported-Codex-model detection/fallback chain and its private helpers (canonicalizeModelName, normalizeFallbackChain, patterns) - url-rewriting.ts (199 lines): extractRequestUrl, rewriteUrlForCodex, proxy resolution (resolveProxyUrlForRequest, applyProxyCompatibleInit, closeSharedProxyDispatchers) and the shared dispatcher cache - headers.ts (99 lines): createCodexHeaders (all overloads) and the RFC 8594 deprecation/sunset header logging fetch-helpers.ts (now 756 lines) remains the re-export facade for every previously-exported symbol, so no importer changes anywhere. Response handling (handleErrorResponse/handleSuccessResponse), rate-limit parsing, and transformRequestForCodex stay in fetch-helpers.ts as they do not fit a seam cleanly. Runtime export surface verified identical before/after; no import cycles introduced. Zero behavior change. Audit roadmap §4.1.2. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
📝 WalkthroughWalkthroughthis pr extracts request handling utilities from ChangesCustom Fetch Request Handling Refactoring
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Review noteserror-classification.ts
token-refresh.ts
url-rewriting.ts
fetch-helpers.ts refactor
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review follow-up: the three symbols that gained export during the split (CHATGPT_CODEX_UNSUPPORTED_MODEL_CODE, isUnsupportedCodexModelForChatGpt, logDeprecationHeaders) exist only for sibling lib/request modules; the facade in fetch-helpers.ts deliberately does not re-export them. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Audit roadmap §4.3 (request layer); stacked on the fetch-helpers split (PR ndycode#524). Inventory result: the request layer is ALREADY fully adopted in code, so this commit is documentation-only — no throw sites changed. Sites already using typed contracts (verified, unchanged): - lib/request/token-refresh.ts:103,112,133 — CodexAuthError (ERROR_MESSAGES.TOKEN_REFRESH_FAILED) with retryable/context/cause; catch sites verified: lib/refresh-guardian.ts:178 uses `instanceof CodexAuthError && !error.retryable`, which holds; test/fetch-helpers.test.ts asserts the exact message and retryable flags. - lib/request/fetch-helpers.ts:212 — intentional rethrow of an error originating in request-transformer.ts (out of scope); left unchanged. Sites left as-is, with reasons: - lib/request/headers.ts:67 — `TypeError: createCodexHeaders requires accountId and accessToken`. The Options-Object Compatibility Contract documents no CodexError subclass for argument misuse, and the native TypeError is a deliberate convention shared with the five other dual-call helpers (parallel-probe, rotation, request-transformer, rate-limit-backoff — all outside this PR's scope). Converting only this site would fracture the convention and change `instanceof TypeError` identity. Tests assert the exact message (test/fetch-helpers.test.ts:614,1834,1843). - lib/request/error-classification.ts / fetch-helpers.ts error mapping — the HTTP/Error Mapping Contract returns normalized Response payloads (stable error.message/error.code), not thrown errors; typed Error classes intentionally do not apply. - lib/request/url-rewriting.ts — no throw sites (native TypeError from the URL constructor is platform behavior asserted by tests). New classes: none needed; lib/errors.ts already defines every shape the documented contracts require. Doc change: docs/reference/error-contracts.md now references the machine-readable types backing the contracts — a "Typed Errors" subsection under the Fetch Helpers contract (CodexAuthError code, message, retryable/cause/context semantics, catch-site guidance) and a note in the Options-Object Compatibility Contract pinning the native TypeError convention for invalid named-parameter calls. Verification: typecheck clean; fetch-helpers, quota-probe, index, index-retry, public-api-contract, chaos/fault-injection, documentation, errors suites: 419/419 passed, identical to base (origin/claude/audit-06-fetch-helpers-split) via git stash comparison. https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Summary
Splits
lib/request/fetch-helpers.ts(1,497 lines, 30+ exports) along its natural seams into four focused modules, per audit roadmap §4.1.2 (docs/audits/AUDIT_2026-06-10.md, PR #522). All code moved verbatim;fetch-helpers.tsremains the re-export facade, so no importer changes and zero behavior change.Changes
lib/request/token-refresh.tsshouldRefreshToken,refreshAndUpdateToken+ private refresh-retry predicateslib/request/error-classification.tsisEntitlementError,isWorkspaceDisabledError,EntitlementError, full unsupported-model fallback machinerylib/request/url-rewriting.tsextractRequestUrl,rewriteUrlForCodex, proxy resolution, shared dispatcher cache + cleanuplib/request/headers.tscreateCodexHeaders(all overloads), RFC 8594 deprecation/sunset warning logginglib/request/fetch-helpers.tsexport *), so the facade's public surface did not grow.exportin their new homes only, for cross-module use:CHATGPT_CODEX_UNSUPPORTED_MODEL_CODE,isUnsupportedCodexModelForChatGpt,logDeprecationHeaders.Validation
npm run typechecknpx eslint lib/request/ --max-warnings=0npx vitest runon all suites referencing fetch-helpers (fetch-helpers,quota-probe,index,index-retry,public-api-contract,chaos/fault-injection): 358/358 passedfetch-helpers/public-api-contractsuites, 151/151Risk / Rollback
Mechanical move with a facade; revert the single commit to roll back. No data, config, or behavior changes.
https://claude.ai/code/session_01XNtnkLbBiXZxfQQYLMpucB
Generated by Claude Code
note: greptile review for oc-chatgpt-multi-auth. cite files like
lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.Greptile Summary
splits
lib/request/fetch-helpers.ts(1,497 lines) along natural seams into four focused modules (token-refresh,error-classification,url-rewriting,headers), keepingfetch-helpers.tsas an explicit re-export facade with zero behavior change. all code is moved verbatim; existing tests (358/358) pass unchanged.export *), preserving the exact public surface; three helpers gain@internalexports in sub-modules for use byfetch-helpers.tsitself, but are not forwarded through the facade.registerCleanup(closeSharedProxyDispatchers)is moved tourl-rewriting.tsmodule-load time; behavior is unchanged since es module singletons guarantee it fires exactly once.Confidence Score: 5/5
mechanical extraction with a re-export facade; all code is verbatim, public surface is byte-identical, and 358 tests pass — safe to merge.
every function, constant, and interface moved verbatim; no logic changes, no import cycles, no new behavior. the only new surface is three @internal-annotated helpers accessible via sub-path imports, which the previous thread already covers. the change is structurally clean.
no files need extra scrutiny; all five files carry straightforward extractions or re-export plumbing.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD FH["fetch-helpers.ts<br/>(facade + response orchestration)"] EC["error-classification.ts<br/>entitlement · model fallback · workspace-disabled"] H["headers.ts<br/>createCodexHeaders · logDeprecationHeaders"] TR["token-refresh.ts<br/>shouldRefreshToken · refreshAndUpdateToken"] UR["url-rewriting.ts<br/>proxy resolution · URL rewrite<br/>+ registerCleanup side-effect"] EC -->|"re-exported via facade"| FH TR -->|"re-exported via facade"| FH UR -->|"re-exported via facade"| FH H -->|"re-exported via facade"| FH FH -->|"internal import"| EC FH -->|"internal import"| H UR -->|"registerCleanup at load"| SD["shutdown.js"] TR -->|"queuedRefresh"| RQ["refresh-queue.js"]Comments Outside Diff (1)
lib/request/url-rewriting.ts, line 1671-1680 (link)getSharedProxyDispatchertwo concurrent callers can both observe
sharedProxyDispatchers.get(proxyUrl) === undefined, both construct a newProxyAgent, and the first agent gets silently overwritten in the map — leaving an unclosedProxyAgentthat is never passed tocloseSharedProxyDispatchers. this is pre-existing code moved verbatim, but isolating it in its own module makes it the single owner ofsharedProxyDispatchers; no other module can close the leaked agent. on windows, an abandonedProxyAgentcan hold an open socket handle that blocks cleanup. consider checking-after-set or using a pending promise to serialize construction.Prompt To Fix With AI
Prompt To Fix All With AI
Reviews (2): Last reviewed commit: "docs(request): mark cross-module helpers..." | Re-trigger Greptile