Commit Graph
266 Commits
Author SHA1 Message Date
Seefs bb234ff418 refactor(responses): remove compact model suffix handling (#6770) 2026-08-11 13:42:32 +08:00
CaIon 1da23d6b33 feat(rate-limit): add user critical rate limit middleware for access token and aff transfer routes 2026-08-07 16:01:22 +08:00
Calcium-Ion 0ab0202060 Feat/auto group (#6590)
* feat(token): support custom auto group order

* feat(keys): enhance auto group presentation

* fix(keys): rework Auto flow border and compact inherited order

The Auto group highlight previously tinted the whole control surface
with a gradient and animated only a 1px top sweep, which read as a
background color rather than a flowing border. Replace it with a
border-only effect: an aria-hidden, pointer-events-none overlay whose
conic gradient is masked down to a thin ring hugging the rounded
perimeter, so the highlight travels around all four edges and corners
every 3.2s. The interior stays neutral with a restrained static
primary border and glow; prefers-reduced-motion hides the moving
layer while keeping the static emphasis.

The inherited global Auto order also rendered as spacious two-line
rows with circular sequence markers, wasting drawer space. Render it
as a compact wrapping strip of one-line chips (index, name, ratio
badge) with descriptions kept accessible via title and sr-only text,
scrolling only past a much smaller max height.

Custom add/remove/reorder editing, empty-array inheritance semantics,
and the submit payload are unchanged.

* fix(keys): preserve Auto inheritance and unify effects

* refactor(keys): temporarily disable AutoGroupBadge in api-key-group-cell
2026-08-01 23:19:01 +08:00
Seefs 0f9f668c60 feat: support zstd request decompression (#6545) 2026-07-31 11:17:55 +08:00
CaIon 8aa5e754a8 refactor: rename trusted_proxies package to middleware and update function calls 2026-07-27 16:48:23 +08:00
Calcium-Ion 86ac0f7745 refactor: extract protocol conversion layer into standalone relaykit module (#6369)
* test(relayconvert): add golden snapshot matrix and relaykit boundary guard

Phase 0 of the relaykit extraction plan: pin byte-level output of every
registered (from,to) request/response/stream conversion route, and
forbid kit-bound packages from growing host-only imports.

* wip(relayconvert): drop gin.Context from converter signatures; add convmeta draft

Phase 1 in progress: relayconvert now takes context.Context; host media
resolver adapts gin.Context back at the service boundary.

* refactor(relayconvert): decouple converters from RelayInfo, gin, and settings

Phase 1 of the relaykit extraction plan:
- converters now depend on convmeta.Meta (implemented by RelayInfo) instead
  of *relaycommon.RelayInfo; ClaudeConvertInfo and the format guesser move
  to convmeta with aliases left behind
- host settings reach converters via a convmeta.Options snapshot built in
  RelayInfo.ConvOptions; no more model_setting/reasoning global reads inside
  the conversion layer
- effort-suffix helpers move to service/relayconvert/reasoning (old package
  forwards); chat-to-responses upgrade policy moves to service (host routing
  logic, not conversion)
- golden conversion matrix unchanged

* test(relayconvert): tighten boundary — kit packages now free of gin/setting imports

* refactor(dto): drop gin and logger dependencies

Phase 2 (part 1): dto.Request.IsStream now takes *http.Request instead of
*gin.Context (Gemini's impl reads query/path off the std request); dto's
three logger calls become common.SysError. Boundary test allowlist is now
empty — kit-bound packages import no gin/setting/logger/model.

* refactor(kit): extract dependency-free kitutil; dto/types/relayconvert stop importing common

Phase 2 of the relaykit extraction plan:
- new service/relayconvert/kitutil holds the pure helpers the kit needs
  (JSON wrappers, pointer/string/uuid/timestamp utils, MaskSensitiveInfo,
  pluggable LogInfo/LogError hooks, Debug flag)
- dto, types, and all relayconvert packages now use kitutil; their only
  remaining internal deps are dto/types/constant
- common keeps every original symbol (MaskSensitiveInfo delegates to
  kitutil) so host code is untouched; main.go routes kit logging into
  common.SysLog/SysError and mirrors DebugEnabled
- golden conversion matrix unchanged

* refactor(kit): move EndpointType/FinishReason to types; OpenRouter dialect via Options

Kit packages (dto/types/relayconvert/reasonmap) no longer import constant:
- EndpointType and finish-reason values live in types; constant re-exports
- the OpenRouter special-case in claude->openai request conversion reads
  Options.OpenRouterDialect, set by the host from the channel type;
  InitChannelMeta invalidates the cached snapshot on channel switch

* refactor: extract relaykit submodule (dto/types/relayconvert/reasonmap)

Phase 3 of the relaykit extraction plan:
- new go module github.com/QuantumNous/new-api/relaykit containing dto
  (minus task family), types, relayconvert (with convmeta/kitutil/reasoning),
  and reasonmap; host consumes it via require + replace, go.work for dev
- task-family dto (task/suno/midjourney/video) stays in the host dto
  package; dual-consumer host files alias it as taskdto
- relaykit builds and tests standalone (GOWORK=off): no host imports,
  no gin, no DB, no settings
- golden conversion matrix unchanged

* build(docker): copy relaykit/go.mod before go mod download

The local-replace submodule's go.mod must exist inside the build context
for the main module graph to resolve.

* fix: address relaykit extraction regressions

* fix: address relaykit review regressions

* docs: document Meta nil receiver contract

* fix(relaykit): fail OpenAI→Claude conversion without max_tokens; reject negative default_max_tokens

The Claude Messages API requires max_tokens (omitting it is a 400
"Field required"), but with a nil Options.Claude.DefaultMaxTokens hook
the converters silently emitted a request the upstream is guaranteed to
reject. Both OpenAI Chat and Responses → Claude conversions now return
sharedclaude.ErrMissingMaxTokens when no path (client value, default
hook, thinking-adapter floor) supplied one. Unreachable in the host,
which always configures the hook.

Host side, claude.default_max_tokens now rejects negative values at the
option API before persisting — they would wrap into huge unsigned values
during conversion. Zero stays allowed: the current API treats
max_tokens: 0 as cache pre-warming.

* fix: make Gemini safety settings read path race-free
2026-07-27 15:56:21 +08:00
CaIon 1721144221 fix(auth): keep login state on rate-limited or failing token refresh
When the dashboard token refresh endpoint returned 429 (shared
critical rate limit) the frontend classified it as out_of_sync,
cleared local auth state, and redirected to /sign-in. The rate limit
itself is working as intended; the bug is that a temporary rejection
was treated as a terminal auth failure.

- Treat 429 refresh responses as transient errors on the frontend,
  keeping the session retryable instead of clearing it. Only explicit
  401 or confirmed session mismatch/race exhaustion clears auth state.
- Return Retry-After on all rate-limited responses (remaining TTL on
  Redis, window duration on the in-memory limiter) so clients can
  back off.
- Log the underlying error with request context when auth session
  errors map to 500 AUTH_INTERNAL_ERROR, and replace fmt.Println with
  request-scoped logging in the Redis rate limiter error paths.

Fixes #6361
2026-07-21 12:39:29 +08:00
Calcium-Ion 31d70fca39 refactor(auth): replace dashboard sessions with stateless tokens and session control (#6329)
* refactor(auth): replace dashboard sessions with stateless tokens

* feat(auth): harden session issuance and distributed enforcement

* fix(proxy): preserve trusted proxy compatibility defaults

* refactor: address dashboard auth review feedback

* refactor: remove classic frontend and flatten web app
2026-07-20 16:48:43 +08:00
Calcium-Ion c36418c863 feat: enhance text protocol conversion and advanced custom routing (#5825)
* refactor: consolidate relay protocol converters

* refactor relayconvert text converters

* feat: refine relay converters and advanced custom routing

* refactor: enhance logging and add thought signature handling for Gemini requests

* refactor: enhance channel cache and pricing endpoint handling for advanced custom models

* feat: preserve billing usage semantics

* feat: add protocol-aware billing usage

* Delete useless files

* chore: update action versions in workflow files

* chore: update Docker action versions in workflow files

* fix: harden billing usage settlement and hot-path route matching

- estimate Gemini completion tokens locally when billable usageMetadata is
  prompt-only but output content was received (e.g. client aborts the stream
  before the final chunk), and rebuild the attached billing_usage as estimated
  so settlement does not bill zero output tokens
- guard NewClaudeMessagesBillingUsage against all-zero ClaudeUsage, matching
  the OpenAI/Gemini constructors, so a zero billing_usage cannot override a
  non-zero top-level usage during settlement
- cache compiled advanced-custom route model regexes; they run on the request
  hot path and were recompiled per request
- move the effectiveBillingUsage remap to PostTextConsumeQuota only, and
  document that calculateTextQuotaSummary expects remapped usage
- document the updatePricingLock -> channelSyncLock lock ordering that
  InitChannelCache/CacheUpdateChannel rely on, and the aux-struct pitfall in
  GeminiChatResponse.UnmarshalJSON
2026-07-11 20:44:12 +08:00
CaIon 56dbaab1d4 feat(session): support opt-in Secure session cookies
- add SESSION_COOKIE_SECURE / SESSION_COOKIE_TRUSTED_URL env vars with
  startup validation: enabling Secure requires at least one trusted
  HTTPS entry URL
- wire common.SessionCookieSecure into the session cookie store instead
  of a hardcoded Secure=false
- print a startup warning when Secure session cookies are disabled
- document the new settings in .env.example and docker-compose files

Secure stays off by default because many deployments front new-api with
plain-HTTP reverse proxies, where a hardcoded Secure default would break
logins entirely; enabling it safely depends on the deployment's TLS
setup, so it ships as an opt-in deployment-hardening flag.
2026-07-05 13:53:16 +08:00
CaIon 0d5995eb63 fix(auth): allow read-only access for non-disabled tokens 2026-07-05 13:35:10 +08:00
Calcium-Ion 4aee5f7d5a feat: better admin permissions (#5755)
* feat: add casbin admin permissions

* feat: improve audit logging to associate logs with actual operators and target users

* feat: enhance admin permissions and UI interactions for sensitive actions

* Refactor authz RBAC and tighten channel permissions

* Split channel authz field policy

* Address channel authz review findings
2026-06-27 17:01:59 +08:00
Calcium-Ion 6dc4030fdf feat: support ClickHouse log database (#5663)
* feat: support ClickHouse log database

* feat(log): optimize log deletion process for ClickHouse
2026-06-22 18:41:26 +08:00
CaIon 55b00fcf09 feat(advanced-custom): remove fallback option and enhance path matching for advanced custom routes 2026-06-18 20:29:24 +08:00
CaIon 1ac0f5807a feat(audit): add authentication method tracking in audit logs 2026-06-13 16:12:22 +08:00
Calcium-Ion d0c4305a16 feat(audit): add localized security audit logs (#5462) 2026-06-12 23:40:40 +08:00
Seefs d2f7f9ee3a fix: limit anonymous request body (#5244)
* fix: limit anonymous request body (env ANONYMOUS_REQUEST_BODY_LIMIT_KB = 512)

* fix: allow disabling anonymous request body limit
2026-06-05 11:39:29 +08:00
XiaoDingSiRenandSeefs 4a188deeaa feat: 支持配置渠道被禁用后是否清空渠道粘性 (#5306)
* fix: evict stale channel affinity

* feat: configure disabled channel affinity retention

---------

Co-authored-by: Seefs <i@seefs.me>
2026-06-05 11:30:29 +08:00
Rain 87cc22d7ec fix(distributor): resolve model for GET /v1/video/generations/:task_id (#5133) 2026-06-04 18:48:30 +08:00
Seefs ae6a03364d perf: optimize request metadata extraction and disabled field filtering (#5009)
* perf: optimize request metadata extraction and disabled field filtering

* perf: optimize stream usage estimation path
2026-05-22 10:32:11 +08:00
yyhhyyyyyy 6f8668e4c3 fix: enforce header nav access control for public modules (#4889) 2026-05-16 14:54:47 +08:00
Seefs 355307223a fix: clarify affinity disabled channel retry message 2026-04-25 17:43:42 +08:00
Seefs 1d83b5472a fix: require proper verification for passkey changes (#4393) 2026-04-22 22:55:06 +08:00
CaIon 59c582d13c fix: harden token auth error handling to prevent info leakage
- Create model/errors.go to centralize all sentinel errors
- ValidateAccessToken now returns error to distinguish DB failures
- ValidateUserToken uses unified ErrTokenInvalid for all auth failures
  (expired/exhausted/disabled/not-found) to prevent token enumeration
- authHelper and TokenAuthReadOnly use i18n messages instead of
  hardcoded Chinese strings
- All err.Error() removed from user-facing responses; DB errors logged
  server-side and return generic "contact admin" message (HTTP 500)
- Migrate ErrRedeemFailed, ErrTwoFANotEnabled to model/errors.go
2026-04-12 17:39:00 +08:00
CaIon 50249f581c refactor(middleware): enhance performance error messages
Updated performance checks to provide more detailed error messages, including current usage and thresholds for CPU, memory, and disk. Additionally. Updated localization files to reflect changes in retry options across multiple languages.
2026-04-02 21:31:35 +08:00
Calcium-Ion c667e4706a Merge pull request #3333 from seefs001/fix/channel-affinity-disable
fix: honor channel affinity skip-retry when channel is disabled
2026-03-23 15:03:23 +08:00
gz1007 a4d1ed6da5 feat: 支持通过环境变量配置搜索接口限流参数 2026-03-18 17:50:23 +08:00
Seefs b09337e6ed fix: honor channel affinity skip-retry when preferred channel is disabled 2026-03-18 16:08:31 +08:00
Seefs e027f38244 feat:add CLI param-override templates with visual editor and apply on first rule match 2026-02-25 15:08:23 +08:00
CaIon 094ac54609 feat(middleware): add RouteTag middleware for enhanced logging and routing
- Introduced RouteTag middleware to set route tags for different API endpoints.
- Updated logger to include route tags in log output.
- Applied RouteTag middleware across various routers including API, dashboard, relay, video, and web routers for consistent logging.
2026-02-25 00:11:24 +08:00
CaIon ba25ba88fe refactor(task): extract billing and polling logic from controller to service layer
Restructure the task relay system for better separation of concerns:
- Extract task billing into service/task_billing.go with unified settlement flow
- Move task polling loop from controller to service/task_polling.go (supports Suno + video platforms)
- Split RelayTask into fetch/submit paths with dedicated retry logic (taskSubmitWithRetry)
- Add TaskDto, TaskResponse generics, and FetchReq to dto/task.go
- Add taskcommon/helpers.go for shared task adaptor utilities
- Remove controller/task_video.go (logic consolidated into service layer)
- Update all task adaptors (ali, doubao, gemini, hailuo, jimeng, kling, sora, suno, vertex, vidu)
- Simplify frontend task logs to use new TaskDto response format
2026-02-22 16:00:27 +08:00
CaIon 4fdd12ac70 feat: Improve backend multilingual support 2026-02-12 14:29:56 +08:00
CaIon 5cf788f1bf refactor: enhance API security with read-only token authentication and improved rate limiting 2026-02-06 21:26:26 +08:00
Calcium-Ion 1bae8928fb Merge commit from fork
fix: harden token search with pagination, rate limiting and input validation
2026-02-06 17:54:40 +08:00
CaIon 327cc5fa23 fix: harden token search with pagination, rate limiting and input validation
- Add configurable per-user token creation limit (max_user_tokens)
- Sanitize search input patterns to prevent expensive queries
- Add per-user search rate limiting (by user ID)
- Add pagination to search endpoint with strict page size cap
- Skip empty search fields instead of matching nothing
- Hide internal errors from API responses
- Fix Interface2String float64 formatting causing config parse failures
- Add float-string fallback in config system for int/uint fields
2026-02-06 17:52:19 +08:00
CaIon a78c1c9be9 fix(i18n): prioritize user settings over Accept-Language header
The i18n middleware runs before UserAuth, so user settings weren't
available when language was detected. Now GetLangFromContext checks
user settings first (set by UserAuth) before falling back to the
language set by middleware or Accept-Language header.
2026-02-05 00:37:18 +08:00
CaIon c444746088 feat(i18n): add backend multi-language support with user language preference
- Add go-i18n library for internationalization
- Create i18n package with translation keys and YAML locale files (zh/en)
- Implement i18n middleware for language detection from user settings and Accept-Language header
- Add Language field to UserSetting DTO
- Update API response helpers with i18n support (ApiErrorI18n, ApiSuccessI18n)
- Migrate hardcoded messages in token, redemption, and user controllers
- Add frontend language preference settings component
- Sync language preference across header selector and user settings
- Auto-restore user language preference on login
2026-02-05 00:09:32 +08:00
CaIon 5e71ef98d9 feat(performance): implement system performance monitoring with configurable thresholds 2026-02-04 21:26:07 +08:00
CaIon 9ef9e78821 feat(file): unify file handling with a new FileSource abstraction for URL and base64 data 2026-02-04 18:23:17 +08:00
Calcium-IonandCursor d7c55b92b2 feat: disk request body cache (#2780)
* feat: 引入通用 HTTP BodyStorage/DiskCache 缓存配置与管理

- 新增 common/body_storage.go 提供 HTTP 请求体存储抽象和文件缓存能力
- 增加 common/disk_cache_config.go 支持全局磁盘缓存配置
- main.go 挂载缓存初始化流程
- 新增和补充 controller/performance.go (及 unix/windows) 用于缓存性能监控接口
- middleware/body_cleanup.go 自动清理缓存文件
- router 挂载相关接口
- 前端 settings 页面新增性能监控设置 PerformanceSetting
- 优化缓存开关状态和模块热插拔能力
- 其他相关文件同步适配缓存扩展

* fix: 修复 BodyStorage 并发安全和错误处理问题

- 修复 diskStorage.Close() 竞态条件,先获取锁再执行 CAS
- 为 memoryStorage 添加互斥锁和 closed 状态检查
- 修复 CreateBodyStorageFromReader 在磁盘存储失败时的回退逻辑
- 添加缓存命中统计调用 (IncrementDiskCacheHits/IncrementMemoryCacheHits)
- 修复 gin.go 中 Seek 错误被忽略的问题
- 在 api-router 添加 BodyStorageCleanup 中间件
- 修复前端 formatBytes 对异常值的处理

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-01-30 01:00:49 +08:00
Seefs cf114ca7d6 feat: openai response /v1/response/compact (#2644)
* feat: openai response /v1/response/compact

* feat: /v1/response/compact bill

* feat: /v1/response/compact

* feat: /v1/responses/compact -> codex channel

* feat: /v1/responses/compact -> codex channel

* feat: /v1/responses/compact -> codex channel

* feat: codex channel default models

* feat: compact model price

* feat: /v1/responses/comapct test
2026-01-26 20:20:16 +08:00
Seefs d9321b7da3 feat: channel affinity (#2669)
* feat: channel affinity

* feat: channel affinity -> model setting

* fix: channel affinity

* feat: channel affinity op

* feat: channel_type setting

* feat: clean

* feat: cache supports both memory and Redis.

* feat: Optimise ui/ux

* feat: Optimise ui/ux

* feat: Optimise codex usage ui/ux

* feat: Optimise ui/ux

* feat: Optimise ui/ux

* feat: Optimise ui/ux

* feat: If the affinitized channel fails and a retry succeeds on another channel, update the affinity to the successful channel
2026-01-26 19:57:41 +08:00
CaIon b311d482e3 fix: update abortWithOpenAiMessage function to use types.ErrorCode 2026-01-19 17:35:28 +08:00
Hackerxiao 815bc61c67 Merge branch 'QuantumNous:main' into main 2025-12-30 11:44:15 +08:00
Seefs 7e1ad4bdff fix: 支持小写bearer和Bearer后带多个空格 && 修复 WSS预扣费错误提取key的问题 2025-12-24 15:52:56 +08:00
t0ng7u fa814b80fe 🧹 fix: harden request-body size handling and error unwrapping
Tighten oversized request handling across relay paths and make error matching reliable.

- Align `MAX_REQUEST_BODY_MB` fallback to `32` in request body reader and decompression middleware
- Stop ignoring `GetRequestBody` errors in relay retry paths; return consistent **413** on oversized bodies (400 for other read errors)
- Add `Unwrap()` to `types.NewAPIError` so `errors.Is/As` can match wrapped underlying errors
- `go test ./...` passes
2025-12-16 18:10:00 +08:00
t0ng7u c2ed76ddfd 🛡️ fix: prevent OOM on large/decompressed requests; skip heavy prompt meta when token count is disabled
Clamp request body size (including post-decompression) to avoid memory exhaustion caused by huge payloads/zip bombs, especially with large-context Claude requests. Add a configurable `MAX_REQUEST_BODY_MB` (default `32`) and document it.

- Enforce max request body size after gzip/br decompression via `http.MaxBytesReader`
- Add a secondary size guard in `common.GetRequestBody` and cache-safe handling
- Return **413 Request Entity Too Large** on oversized bodies in relay entry
- Avoid building large `TokenCountMeta.CombineText` when both token counting and sensitive check are disabled (use lightweight meta for pricing)
- Update READMEs (CN/EN/FR/JA) with `MAX_REQUEST_BODY_MB`
- Fix a handful of vet/formatting issues encountered during the change
- `go test ./...` passes
2025-12-16 17:00:19 +08:00
CaIon 692b5ff5ac feat(auth): refactor IP restriction handling to use clearer variable naming 2025-12-15 20:13:09 +08:00
CaIon 947a763a1a feat(auth): enhance IP restriction handling with CIDR support 2025-12-15 17:24:09 +08:00
CaIon 6175f254a2 refactor(channel_select): enhance retry logic and context key usage for channel selection 2025-12-13 16:43:38 +08:00