修复众多功能#7
Merged
Merged
Conversation
This option was removed in TypeScript 5.5+. Use noImplicitAny: false (already set) to suppress implicit any errors instead. Fixes: error TS5102: Option 'suppressImplicitAnyIndexErrors' has been removed. Co-authored-by: zhaiker01 <285887163+zhaiker01@users.noreply.github.com>
- Fix import paths: '../../shared/types' -> '../shared/types' in oauth/types
and providers/custom (file is at backend/shared/types, not /shared/types).
- shared/types: import LegacyToolPromptConfig and ToolCallingConfig as types
before re-exporting so they're available in local scope (fixes TS2304).
- shared/types: add credentialFields to Provider interface so providers/
custom.ts can construct Provider with credentialFields.
- store/types: add credentialFields to Provider so accountUtils can read it.
- oauth/types: add 'token' to TokenType union (used by deepseek/minimax
ManualTokenConfig entries).
- oauth/types: relax MANUAL_TOKEN_CONFIGS to Partial<Record<...>> so it
doesn't need entries for every ProviderType (mimo, zai are not configured).
- proxy/adapters/index: PerplexityStreamHandler lives in perplexity-stream,
not perplexity.
- proxy/adapters/prompt: convert getPromptVariant() PromptVariant|null
results to PromptVariant|undefined where needed (TransformResult.variant
and toolsToPrompt() expect undefined, not null).
- proxy/adapters/prompt: guard part.text type narrowing before push.
- proxy/adapters/prompt/DefaultPromptAdapter: import TOOL_PROMPT_SIGNATURES
from utils/tools (where it's defined) instead of constants/signatures.
- proxy/index: routes/index.ts only has a default export; use
'export { default as routes }'.
- proxy/utils/accountUtils: default account name to '' when accountInfo is
undefined (Account.name is required).
- proxy/utils/clientDetector: look up promptSectionMarkers via
CLIENT_SIGNATURES[clientType] instead of from DetectionResult (which
doesn't carry that field).
- proxy/utils/index: avoid duplicate re-exports between toolParser/index
and the deprecated streamToolHandler (createBaseChunk, flushToolCallBuffer,
shouldBlockOutput).
- store/store: export StoreManager class.
- store/index: import storeManager so initializeStore() can call it.
The createAccount helper was returning userId, usageCount, and metadata, none of which exist on the Account interface (which uses requestCount, not usageCount, and does not track userId or metadata). Drop them to match the declared return type Omit<Account, 'id' | 'createdAt' | 'updatedAt'>. Fixes: error TS2353: Object literal may only specify known properties, and 'userId' does not exist in type 'Omit<Account, ...>'.
The Logs page imports { RequestLogList } from '@/components/logs', but the
component never existed in this repo, causing vite build to fail with:
[vite:load-fallback] Could not load .../frontend/src/components/logs
Add a real implementation that:
- Lists request logs in a table (time, status, model, provider, account, latency)
- Supports search and status filtering (all/success/error)
- Auto-refreshes every 5 seconds and on demand
- Lets the user clear all logs (with confirm dialog)
- Opens a detail dialog with tabs (Info, User Input, Request, Response, Error)
Also:
- Export the RequestLogEntry type from @shared/types so api.ts and the new
component can import it from a single location.
- Update .gitignore: the existing 'logs/' rule was unintentionally hiding
the new components/logs source folder. The un-ignore line still pointed
at the old Electron path src/renderer/src/components/logs/, so add
!frontend/src/components/logs/ for the post-migration layout.
The handler for GET / was setting ctx.status = 404 and returning, with a comment saying 'let the static fallback render index.html'. But koa-router will not invoke later middleware if the handler returns without calling next(), so the static asset fallback (which knows how to serve index.html) never ran. Browsers hitting http://host:8080/ saw a bare 404. Accept next as a parameter and await it instead of returning, so the fallback in the trailing app.use() runs and serves index.html. Sub-routes already worked because they never matched this handler.
The API key middleware allow-listed only '/', '/health', '/stats' and '/v0/management/*'. Everything else (including the SPA's own /assets/*.js, /assets/*.css, *.png, and any client-side route like /dashboard) was forced through API key validation. As soon as an operator turned on 'Enable API Key' from the management UI, the next page load fetched /assets/index-XXXX.js, hit the gate without an Authorization header, and got a 401. The browser then rendered a blank page because the SPA bundle never executed. Restrict the gate to the OpenAI-compatible proxy endpoints (/v1/*), which is the only surface the key was ever meant to protect. The management API still has its own auth; the SPA bundle is now served without authentication, the same way every other SPA-host setup does.
The /v0/management/oauth/bookmarklet/ingest endpoint is the only
management route that legitimately accepts cross-origin requests —
operators run the bookmarklet from the provider's own site
(chatglm.cn, chat.deepseek.com, ...) and POST the captured token
back here. The endpoint authenticates with a one-shot ticket baked
into the bookmarklet, not with cookies, so wildcard CORS is safe.
The route handler in routes/management/oauth/bookmarklet.ts already
sets Access-Control-Allow-Origin: * for itself, but the global CORS
middleware in setupMiddleware() runs first and:
1. Refuses to emit CORS headers for /v0/management/* unless the
Origin is in CHAT2API_CORS_ORIGINS (which obviously won't list
every AI provider's domain).
2. Short-circuits OPTIONS with status 204 BEFORE the request
reaches the router, so the route-level CORS setup never runs
for preflight.
Net result: GLM bookmarklet (and every other provider's) sees the
preflight come back without Access-Control-Allow-Origin and aborts
with 'Failed to fetch'.
Special-case the ingest path in the global middleware so it gets
Allow-Origin:* on both the preflight and the POST. Other management
routes still go through the strict whitelist.
After the bookmarklet flow finishes, the backend GLM adapter returns
credentials as { refreshToken, accessToken } (camelCase), but the form
field is named 'refresh_token' (snake_case) and the old mapper was
looking for 'chatglm_refresh_token' (the raw cookie name) - so the
mapping silently failed and the UI complained 'fill required field:
Refresh Token' even though we already had the token in hand.
Replace the per-provider single-key map with a list of candidate keys.
For each provider we now try every name the OAuth path may emit (raw
cookie names, the bookmarklet's relabelled 'token' field, snake_case,
and the camelCase keys the adapters actually return) and pick the
first non-empty value. The candidate gets written into the form field
the credentialFields config expects.
The OAuth success handler was calling setCredentials() and
setActiveTab('manual') in the same synchronous batch. When
React renders the tab content for 'manual', the credential fields
component mounts fresh — but because the state update for credentials
may not have been committed yet when the TabsContent mounts, the
fields render as empty.
Fix: switch tab first (so the fields mount), then set credentials
in a setTimeout(0) microtask so React can flush the tab switch
before filling the inputs. Also add console.log so operators can
see exactly what the OAuth flow returned and what got mapped.
The old BookmarkletPanel required users to drag a link into their bookmark bar, navigate to the provider page, and click the bookmark. This was confusing and often failed due to CORS/mixed-content issues when the backend runs on a different server. Replace with ConsoleScriptPanel — a much simpler flow: 1. Click 'Generate Script' (issues a ticket on the backend) 2. Click 'Copy Script' (copies one-line JS to clipboard) 3. Open provider page (e.g. chatglm.cn), F12 → Console → Paste → Enter 4. Script reads token from cookie/localStorage and POSTs to backend 5. Panel auto-polls and picks up the result Changes: - New: frontend/src/components/oauth/ConsoleScriptPanel.tsx - Modified: TokenExtractionGuide now renders ConsoleScriptPanel instead of BookmarkletPanel as the primary OAuth capture method - Added oauth.console i18n keys (bilingual zh-CN / en-US) with step-by-step instructions - BookmarkletPanel.tsx is kept in the repo (backend ingest endpoint still works) but no longer referenced from the UI The backend bookmarklet ingest endpoint is unchanged — the console script uses the exact same ticket/ingest/poll API, just triggered from a pasted script instead of a dragged bookmark.
Replace the ticket/fetch/polling ConsoleScriptPanel with a dead-simple
version that just shows a per-provider one-liner JS command:
GLM: document.cookie.match(/chatglm_refresh_token=([^;]+)/)?.[1]
DeepSeek: localStorage.getItem('userToken')
Kimi: document.cookie.match(/kimi-auth=([^;]+)/)?.[1]
Qwen: document.cookie.match(/tongyi_sso_ticket=([^;]+)/)?.[1]
etc.
User flow is now:
1. Click 'Copy Command' in Chat2API
2. Go to provider page → F12 → Console → Paste → Enter
3. Right-click the returned value → 'Copy string'
4. Paste into the token field in Chat2API → Add Account
No bookmarklets, no tickets, no auto-POST, no CORS issues.
The old BookmarkletPanel and backend ingest endpoint remain in the
codebase (they still work) but are no longer referenced from the UI.
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.
修复众多功能