refactor: consolidate single-source routing and protocol helpers

This commit is contained in:
Cita
2026-03-22 21:27:09 +08:00
parent 96e7614835
commit 9290e51ecc
64 changed files with 3571 additions and 2681 deletions
@@ -0,0 +1,254 @@
# Single Source Consolidation PR1 Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Land PR1 for the highest-value duplication and double-source issues around responses normalization, shared proxy surface orchestration, provider runtime headers, token-route contract sharing, account mutation workflow, and standard API platform helpers.
**Architecture:** Keep PR1 focused on extracting shared single-source modules and rewiring existing callers to consume them. Do not expand this PR into schema metamodel rewrites, `chatFormatsCore` breakup, or mobile page scaffold work; those remain follow-up PR scope once the highest-risk protocol and workflow duplications are removed.
**Tech Stack:** TypeScript, Fastify, Vitest, shared server/web modules under `src/shared`, server proxy-core surfaces/providers/services, React admin pages.
---
### Task 1: Savepoint Commit
**Files:**
- Commit: `src/server/config.ts`
- Commit: `src/server/config.test.ts`
- Commit: `src/server/db/proxyFileSchemaCompatibility.ts`
- Commit: `src/server/db/proxyFileSchemaCompatibility.test.ts`
**Step 1: Verify the savepoint changes**
Run: `npm test -- src/server/config.test.ts src/server/db/proxyFileSchemaCompatibility.test.ts`
Expected: PASS
**Step 2: Commit the savepoint**
Run:
```bash
git add src/server/config.ts src/server/config.test.ts src/server/db/proxyFileSchemaCompatibility.ts src/server/db/proxyFileSchemaCompatibility.test.ts
git commit -m "fix: trust proxy headers and align proxy file mysql indexes"
```
**Step 3: Cherry-pick into PR1 branch**
Run:
```bash
git cherry-pick <savepoint-commit>
```
Expected: first commit preserved inside PR1 branch before the larger consolidation commit.
### Task 2: Responses Single Source
**Files:**
- Create: `src/server/transformers/openai/responses/normalization.ts`
- Modify: `src/server/transformers/openai/responses/conversion.ts`
- Modify: `src/server/transformers/openai/responses/compatibility.ts`
- Test: `src/server/transformers/openai/responses/conversion.test.ts`
**Step 1: Move shared normalization helpers into one source**
Keep `normalizeResponsesInputForCompatibility`, `normalizeResponsesMessageContent`, and related block normalization in `normalization.ts`.
**Step 2: Rewire both callers**
Make `conversion.ts` and `compatibility.ts` import the shared helpers instead of maintaining their own independent copies.
**Step 3: Verify parity**
Run: `npm test -- src/server/transformers/openai/responses/conversion.test.ts`
Expected: PASS, including assertions that compatibility exports point at the shared implementation.
### Task 3: Shared Surface Orchestration
**Files:**
- Create: `src/server/proxy-core/surfaces/sharedSurface.ts`
- Modify: `src/server/proxy-core/surfaces/chatSurface.ts`
- Modify: `src/server/proxy-core/surfaces/openAiResponsesSurface.ts`
- Modify: `src/server/proxy-core/surfaces/geminiSurface.ts`
- Test: `src/server/proxy-core/surfaces/sharedSurface.test.ts`
**Step 1: Extract common orchestration primitives**
Centralize channel selection, dispatch, proxy logging, retry/failure handling, and common failure response shaping in `sharedSurface.ts`.
**Step 2: Rewire surface callers**
Make chat and responses surfaces consume the shared orchestration helpers instead of each keeping a parallel flow.
**Step 3: Verify behavior**
Run: `npm test -- src/server/proxy-core/surfaces/sharedSurface.test.ts`
Expected: PASS
### Task 4: Provider Header Builders
**Files:**
- Create: `src/server/proxy-core/providers/headerUtils.ts`
- Modify: `src/server/proxy-core/providers/codexProviderProfile.ts`
- Modify: `src/server/proxy-core/providers/claudeProviderProfile.ts`
- Modify: `src/server/proxy-core/providers/geminiCliProviderProfile.ts`
- Modify: `src/server/routes/proxy/upstreamEndpoint.ts`
- Test: `src/server/proxy-core/providers/headerUtils.test.ts`
**Step 1: Extract header parsing and runtime header construction**
Keep Codex, Claude, and Gemini CLI runtime header shaping in `headerUtils.ts`.
**Step 2: Remove duplicate builders**
Make both provider profiles and `upstreamEndpoint.ts` call the shared header builders.
**Step 3: Verify behavior**
Run: `npm test -- src/server/proxy-core/providers/headerUtils.test.ts`
Expected: PASS
### Task 5: Cross-Layer Token Route Contract
**Files:**
- Create: `src/shared/tokenRouteContract.js`
- Create: `src/shared/tokenRouteContract.d.ts`
- Create: `src/shared/tokenRoutePatterns.js`
- Create: `src/shared/tokenRoutePatterns.d.ts`
- Modify: `src/server/services/tokenRouter.ts`
- Modify: `src/server/routes/api/tokens.ts`
- Modify: `src/web/pages/token-routes/utils.ts`
- Modify: `src/web/pages/token-routes/types.ts`
- Modify: `src/web/pages/helpers/routeListVisibility.ts`
- Modify: `src/web/pages/Settings.tsx`
- Test: `src/shared/tokenRouteContract.test.ts`
- Test: `src/shared/tokenRoutePatterns.test.ts`
**Step 1: Extract shared route mode and pattern matching**
Make route mode normalization and model pattern matching authoritative in `src/shared`.
**Step 2: Rewire server and web**
Make token router, route APIs, token-routes helpers, and settings consume the shared contract instead of maintaining separate copies.
**Step 3: Verify behavior**
Run: `npm test -- src/shared/tokenRouteContract.test.ts src/shared/tokenRoutePatterns.test.ts`
Expected: PASS
### Task 6: Account Mutation Workflow
**Files:**
- Create: `src/server/services/accountMutationWorkflow.ts`
- Modify: `src/server/routes/api/accounts.ts`
- Modify: `src/server/routes/api/accountTokens.ts`
- Test: `src/server/services/accountMutationWorkflow.test.ts`
**Step 1: Extract convergence workflow**
Move token sync, default token ensure, balance refresh, model refresh, and route rebuild sequencing into `accountMutationWorkflow.ts`.
**Step 2: Rewire controllers**
Make account and account-token APIs call the workflow service instead of each owning private orchestration logic.
**Step 3: Verify behavior**
Run: `npm test -- src/server/services/accountMutationWorkflow.test.ts`
Expected: PASS
### Task 7: Standard API Provider Base
**Files:**
- Create: `src/server/services/platforms/standardApiProvider.ts`
- Modify: `src/server/services/platforms/openai.ts`
- Modify: `src/server/services/platforms/claude.ts`
- Modify: `src/server/services/platforms/gemini.ts`
- Modify: `src/server/services/platforms/cliproxyapi.ts`
- Test: `src/server/services/platforms/standardApiProvider.test.ts`
- Test: `src/server/services/platforms/llmUpstream.test.ts`
**Step 1: Extract shared standard API adapter logic**
Centralize base URL normalization, `/v1/models` resolution, unsupported login/checkin/balance defaults, and common model fetch behavior.
**Step 2: Rewire adapters**
Make OpenAI, Claude, Gemini, and CLIProxyAPI adapters extend the shared base instead of repeating the same template logic.
**Step 3: Verify behavior**
Run: `npm test -- src/server/services/platforms/standardApiProvider.test.ts src/server/services/platforms/llmUpstream.test.ts`
Expected: PASS
### Task 8: Shared Input File Resolution And Web Helpers
**Files:**
- Modify: `src/server/services/proxyInputFileResolver.ts`
- Modify: `src/server/services/proxyInputFileResolver.test.ts`
- Modify: `src/server/proxy-core/surfaces/inputFilesSurface.ts`
- Create: `src/web/pages/helpers/accountConnection.ts`
- Create: `src/web/pages/helpers/accountConnection.test.ts`
- Modify: `src/web/pages/Accounts.tsx`
- Modify: `src/web/pages/Tokens.tsx`
- Modify: `src/web/api.ts`
- Modify: `src/web/api.test.ts`
**Step 1: Make route-level file inlining reuse the service implementation**
Replace the duplicate `inputFilesSurface.ts` implementation with a re-export of the shared resolver service.
**Step 2: Extract shared web account helpers**
Move `resolveAccountCredentialMode`, `parsePositiveInt`, and `isTruthyFlag` into a single helper consumed by both Accounts and Tokens.
**Step 3: De-duplicate proxy test aliases**
Make `testProxy` / `proxyTest` and stream variants reuse the same implementation function.
**Step 4: Verify behavior**
Run: `npm test -- src/server/services/proxyInputFileResolver.test.ts src/web/pages/helpers/accountConnection.test.ts src/web/api.test.ts`
Expected: PASS
### Task 9: PR1 Verification And Commit
**Files:**
- Verify: `scripts/dev/copy-runtime-db-generated.ts`
- Verify: `scripts/dev/copy-runtime-db-generated.test.ts`
- Verify: all files touched in Tasks 2-8
**Step 1: Run focused regression suite**
Run:
```bash
npm test -- scripts/dev/copy-runtime-db-generated.test.ts src/server/proxy-core/cliProfiles/codexProfile.test.ts src/server/proxy-core/providers/headerUtils.test.ts src/server/proxy-core/surfaces/sharedSurface.test.ts src/server/routes/api/oauth.test.ts src/server/services/accountMutationWorkflow.test.ts src/server/services/modelService.discovery.test.ts src/server/services/oauth/oauthAccount.test.ts src/server/services/platforms/standardApiProvider.test.ts src/server/services/platforms/llmUpstream.test.ts src/server/services/proxyInputFileResolver.test.ts src/server/transformers/openai/responses/conversion.test.ts src/shared/tokenRouteContract.test.ts src/shared/tokenRoutePatterns.test.ts src/web/api.test.ts src/web/pages/helpers/accountConnection.test.ts
```
Expected: PASS
**Step 2: Run server build**
Run: `npm run build:server`
Expected: PASS
**Step 3: Commit PR1 consolidation work**
Run:
```bash
git add docs/plans/2026-03-22-single-source-consolidation-pr1.md scripts/dev/copy-runtime-db-generated.test.ts scripts/dev/copy-runtime-db-generated.ts src/server/proxy-core/cliProfiles/codexProfile.ts src/server/proxy-core/cliProfiles/codexProfile.test.ts src/server/proxy-core/providers/headerUtils.ts src/server/proxy-core/providers/headerUtils.test.ts src/server/proxy-core/providers/claudeProviderProfile.ts src/server/proxy-core/providers/codexProviderProfile.ts src/server/proxy-core/providers/geminiCliProviderProfile.ts src/server/proxy-core/surfaces/chatSurface.ts src/server/proxy-core/surfaces/geminiSurface.ts src/server/proxy-core/surfaces/inputFilesSurface.ts src/server/proxy-core/surfaces/openAiResponsesSurface.ts src/server/proxy-core/surfaces/sharedSurface.ts src/server/proxy-core/surfaces/sharedSurface.test.ts src/server/routes/api/accountTokens.ts src/server/routes/api/accounts.ts src/server/routes/api/oauth.test.ts src/server/routes/api/tokens.ts src/server/routes/proxy/downstreamClientContext.ts src/server/routes/proxy/responsesWebsocket.ts src/server/routes/proxy/upstreamEndpoint.ts src/server/services/accountMutationWorkflow.ts src/server/services/accountMutationWorkflow.test.ts src/server/services/backupService.ts src/server/services/modelService.discovery.test.ts src/server/services/modelService.ts src/server/services/oauth/oauthAccount.ts src/server/services/oauth/oauthAccount.test.ts src/server/services/oauth/quota.ts src/server/services/oauth/service.ts src/server/services/platforms/claude.ts src/server/services/platforms/cliproxyapi.ts src/server/services/platforms/gemini.ts src/server/services/platforms/llmUpstream.test.ts src/server/services/platforms/openai.ts src/server/services/platforms/standardApiProvider.ts src/server/services/platforms/standardApiProvider.test.ts src/server/services/proxyInputFileResolver.ts src/server/services/proxyInputFileResolver.test.ts src/server/services/siteProxy.ts src/server/services/tokenRouter.ts src/server/transformers/anthropic/messages/inbound.ts src/server/transformers/openai/responses/compatibility.ts src/server/transformers/openai/responses/conversion.test.ts src/server/transformers/openai/responses/conversion.ts src/server/transformers/openai/responses/normalization.ts src/shared/tokenRouteContract.d.ts src/shared/tokenRouteContract.js src/shared/tokenRouteContract.test.ts src/shared/tokenRoutePatterns.d.ts src/shared/tokenRoutePatterns.js src/shared/tokenRoutePatterns.test.ts src/web/api.ts src/web/api.test.ts src/web/pages/Accounts.tsx src/web/pages/Settings.tsx src/web/pages/Tokens.tsx src/web/pages/helpers/accountConnection.ts src/web/pages/helpers/accountConnection.test.ts src/web/pages/helpers/routeListVisibility.ts src/web/pages/token-routes/types.ts src/web/pages/token-routes/utils.ts
git commit -m "refactor: consolidate single-source routing and protocol helpers"
```
### Deferred After PR1
**Keep out of this PR:**
- `shared/chatFormatsCore.ts` breakup
- Gemini `generate-content` module boundary cleanup
- schema contract/introspection meta-rule unification
- `legacySchemaCompat.ts` feature compatibility dedupe
- mobile page scaffold extraction
- large-file decomposition for `Settings.tsx`, `ModelTester.tsx`, `tokenRouter.ts`, `modelService.ts`