Preserve legacy credentials across primary RP ID changes and bind successful
assertions to their verified RP ID. Share domain selection across sign-in,
login verification and sensitive operations without replaying ceremonies.
Save domain settings atomically, preview known and unknown credential impact,
and require fresh confirmation before removing domains still in use. Recheck
trusted RP IDs when persisting credentials and record safe operation audits.
Use read-only configuration snapshots, accept trusted HTTPS intranet hosts,
check registration origins early, and preserve historical capitalization.
Update settings guidance and all supported translations.
Validation: SQLite 3.50.4, MySQL 8.0.46 and PostgreSQL 16.15, including fresh
and released-schema upgrade checks; Go regression and race checks; 79 frontend
tests; TypeScript, lint, frontend build and root Go build.
Security references: OWASP ASVS 5.0.0 V6.3.4 and V6.3.8, Authentication and
Session Management Cheat Sheets, and the WebAuthn RP ID/origin rules.
Expose supported channel types in plugin options and let channel editors select extension models using the existing channel connection settings.
Add a gateway category, refine provider ordering and presentation, and prefer available plugins for legacy task providers during channel creation. Include the related translations and regression tests.
Validation in an isolated snapshot: 123 channel frontend tests, the plugin-options controller regression, TypeScript checks, affected-file lint, protected-header formatting, and the production frontend build passed.
Preserve existing keys when updating random or polling selection, and omit the strategy for single-key channels. Validated with 46 configuration tests, type checks, lint, and formatting checks.
- Share provider selection and tabbed configuration across channel creation and editing.
- Add provider descriptions, custom categories, inline model discovery, and model configuration tools.
- Improve batch model input, model mapping labels, parameter overrides, and required field indicators.
- Preserve existing Passkey domains and confirm domain changes.
- Include translations and regression coverage for the updated workflows.
Validation: 113 frontend tests, TypeScript checks, affected-file lint, production build, and protected-header formatting checks passed.
Add reviewed legacy-to-expression draft conversion with effective prices and provider billing adjustments. Standardize preview response handling and preserve explicit zero values, currency conversion, and save conflict detection. Reuse ConfirmDialog, CopyButton, and existing pricing preview components.
Add tier(name, fixed(usd)) pricing leaves to conditional token expressions,
with static validation, token/request billing metadata, and safe settlement
when successful requests have missing or zero token usage. Preserve group
and request multipliers, separate tool charges, and explicit zero prices.
Reject fixed expressions on unsupported Realtime and task-usage entrances.
Expose per-token and per-call tier editing, preserve both drafts, and show
request units consistently in pricing summaries and consume logs. Retain
matched-branch metadata and update all seven frontend locales.
Validation passed:
- go test ./pkg/billingexpr ./relay/helper ./service ./setting/billing_setting ./relay -count=1
- Frontend pricing, model-pricing, editor and usage-log regression suites
- Typecheck, scoped lint, protected-header formatting, i18n validation and build
- go test ./service -run TestFixedPriceBillingDatabaseMatrix -count=1 -v
with TEST_FIXED_MYSQL_DSN and TEST_FIXED_POSTGRES_DSN set to isolated local
test databases: SQLite 3.50.4, MySQL 8.0.46, PostgreSQL 16.15.
All 39 database cases passed, including reserve/settle/refund, zero price,
missing usage, branch changes and insufficient-quota handling.
No production database schema or migration changes.
Move the current pricing summary and save errors into the editor scroll
container through its optional scrollHeader slot. Keep the save controls
available without nesting a separate capped scroll area above the editor.
Validation: model-pricing and related frontend regression tests, typecheck,
scoped lint, and protected-header formatting passed.
Preserve backend details and error causes, and report each failed operation
once across request, Query/Mutation, and page handling layers. Independent
operations with the same error message still receive separate notifications.
Migrate direct requests and query consumers, preserve inline and silent error
handling, and reject failed settings writes before success callbacks run.
Retain safe authentication messages, refresh behavior, and single-use proof
replay protection.
Validation: independently checked the staged snapshot with 117 frontend test
files (1105 tests), typecheck, scoped lint, and protected-header formatting.
Security references: OWASP ASVS 5.0.0, Authentication Cheat Sheet, and
Session Management Cheat Sheet:
https://owasp.org/www-project-application-security-verification-standard/https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.htmlhttps://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
Add confirmed multi-select deletion through one batch API request and one
soft-delete statement. Record the affected count and requested IDs in a
separate batch audit event, and identify legacy events with missing counts.
After creation, offer an unchecked Save as a file option with TXT/Markdown
formats and optional name/quota fields. Keep Done as the default completion
action. Include translations for all seven frontend locales.
Validation:
- Redemption and audit frontend regression tests, typecheck, and scoped lint.
- go build ./...
- go test ./controller -run '^TestDeleteRedemptionBatch$' -count=1 -v
with TEST_MYSQL_DSN, TEST_MYSQL_LOG_DSN, TEST_POSTGRES_DSN,
and TEST_POSTGRES_LOG_DSN set to isolated primary and log databases.
- Real SQLite 3.50.4, MySQL 8.4.11, and PostgreSQL 16.15 passed, including
deletion of 15 records, duplicate/missing IDs, zero-row retries, audit
deduplication, invalid input, and exclusion of credentials from logs.
Bound desktop quota content to 180px so column width provides whitespace before the group column. Remove the quota-only padding override to use the same cell padding as other columns. Preserve the mobile quota layout.
Validation: layout regressions failed before the fix and all 26 API key listing tests passed afterward. TypeScript, scoped lint, formatting, production build, and git diff checks passed.
Increase the quota column width and minimum width from 220px to 260px to give the side-by-side amounts more room.
Validation: all 26 API key listing tests, TypeScript, scoped lint, formatting, and git diff checks passed.
Place remaining quota on the left and used quota on the right above the progress bar, without visible labels in desktop rows. Preserve accessible descriptions and the existing mobile labels and stacked layout.
Validation: updated regressions failed before the change and all 26 API key listing tests passed afterward. TypeScript, scoped lint, formatting, production build, and git diff checks passed.
Reuse the shared Combobox to suggest groups for the active log view while allowing historical group names to be entered manually. Exclude the automatic routing pseudo-group from suggestions and preserve masking, reset, URL navigation, and mobile drawer behavior.
Extend the existing Combobox with keyboard event forwarding and accessible labels, preserve the selected custom value on focus, and close suggestions on blur. Enter confirms a selection before submitting the filter.
Validation: 25 tests passed across the shared Combobox and log group, type, and mobile filter suites. TypeScript, scoped lint, formatting, and git diff checks passed.
Show remaining and used API key quota with a progress bar, and use consistent mobile cards, group multiplier badges, and activity timestamps. Present available user balance with used quota underneath and translate the new labels.
Resolve full API keys only for explicit copy or chat actions. Reviewed OWASP Authentication and Session Management guidance and ASVS 5.0.0 V14.2.6 and V8.3.1; backend authorization is unchanged, and regression tests cover refused and denied key resolution. This frontend change does not assert application-wide ASVS compliance.
Validation: 55 related component tests passed; the latest mobile group and quota changes passed 35 focused tests. TypeScript, scoped lint, formatting, production build, and git diff checks passed. Responsive previews verified narrow screens and finite, unlimited, exhausted, and inactive quota states.
Include configured channel models without creating metadata, derive square
visibility from live routes and metadata policy, and filter before pagination.
Share pricing display with the model square, show expression tiers and task
unit prices, preserve zero rates, and expose full pricing and visibility
reasons from compact responsive rows. Complete all seven locale translations.
Validated frontend tests, typecheck, lint and production build, plus the
model database matrix on SQLite 3.50.4, MySQL 5.7.44 and PostgreSQL 9.6.24.
The model card grid and its loading skeleton only reached three columns at
2xl, leaving a two-column layout on common desktop widths. Use the xl
breakpoint for both and lock it with a test.
The perf summary API only returned the last three non-empty buckets as
bare success rates, so the 24-slot status strip on model cards never lit
more than three bars and could not show hours without traffic.
Replace recent_success_rates with recent_success_series: one timestamped
point per hour that had requests, aligned to hour start regardless of
the configured bucket size. The badge now anchors its 24 slots to the
client's current hour and places each point by timestamp, leaving hours
without data gray.
- Portal Combobox and Select popups into the vaul DrawerContent via a
portal-container context so they stay inside the Radix modal layer
instead of inheriting body pointer-events: none
- Provide an in-memory localStorage/sessionStorage in test-setup when the
Node 25+ global accessor resolves to undefined and shadows jsdom
- Add regression tests for popups rendered inside and outside the drawer
Introduce a unified model management experience: catalog metadata
validation, vendor management, batch delete with channel/pricing
cleanup, model pricing snapshot editing with optimistic concurrency,
and an upstream ratio-sync flow with price cells. Move configuration
into dedicated pricing config/metadata-sync/vendor-management backend
services and add audit records for model/vendor/pricing mutations.
Rework the models page around vendors and model connections, add
model-pricing and vendor-management dialogs, and replace the shared
Select usages with the Combobox component across subscriptions,
plugins, OAuth presets, audit filters, and settings. Add the model
pricing panel and verify behavior with focused tests.
Treat TOTP and Passkey as alternative enrolled factors across login and
sensitive account operations. Gate every primary login transport before
issuing a session, require WebAuthn user verification, and consume login
challenges atomically with session creation.
Reuse the shared verification UI for login, 2FA management, and account
deletion. Require scoped, single-use deletion proof; recheck the session
inside the deletion transaction and revoke all sessions afterward.
Validation: controller/service/model/middleware tests; real SQLite 3.50.4,
MySQL 8.4.11, and PostgreSQL 16.15 security regressions; frontend tests,
TypeScript, targeted lint, formatting, and production build.
Deploy the frontend and all backend nodes together. No schema changes.
Record successful and failed API token operations with safe target metadata. Capture quota adjustments in a transaction, synchronize committed cache differences, and correlate audit and top-up records.
Show operation targets, changes, quota balances, and failure details consistently across audit and usage logs, with translations for all seven locales.
Validated controller, middleware, and model tests; 78 frontend tests; typecheck and lint; real SQLite 3.50.4, MySQL 8.4.11, and PostgreSQL 16.15 with shared and separate log databases.
Require scoped, single-use verification for account bindings and password
operations. Bind OAuth authorization and email confirmations to the initiating
session; preserve the last usable login method and audit operation outcomes.
Apply Unicode-aware password length limits, Argon2id writes with bcrypt
compatibility, and long-password encryption.
Return has_password with the existing profile SELECT without extra queries.
Reuse the existing security dialogs and add all seven locale translations.
Validation:
- Go: go test ./common ./model ./service ./middleware ./controller ./router -count=1
- DB: SQLite 3.50.4, MySQL 8.4.11, PostgreSQL 16.15; separate main/log databases
- MySQL/PostgreSQL: TEST_SECURITY_DIALECT=<dialect> with TEST_<DIALECT>_DSN,
go test ./controller -run '^(TestSecurityAccount|TestSecurityEnrollment|TestGenerateOAuthCode|TestOAuthBind|TestTelegramOAuth)' -count=1 -v
- Web: relevant Vitest suites, bun run typecheck, targeted oxlint/format,
bun run i18n:sync, and bun run build
Roll out dual-format readers to every instance with
ACCOUNT_PASSWORD_HASH_ALGORITHM=bcrypt before enabling Argon2id writes
and the new UI. Rollbacks must retain Argon2id and v2 envelope readers.
Relevant controls: ASVS 5.0.0 6.2.1-6.2.3, 6.2.5-6.2.9, 6.3.7, 7.4.3, 7.5.1;
this change does not assert application-wide ASVS certification.
Use authorization code flow with PKCE and verified ID tokens for Telegram login, binding, and security verification. Preserve existing bindings and require administrator OAuth configuration.
Keep the restricted WeChat first-enrollment session proof, fix missing-target authentication errors, and preserve callback requests after OAuth popups close.
Require single-use operation proofs for passkey enrollment, two-factor setup, and channel key access. Add password and OAuth verification flows, enforce session-bound enrollment, and redact OAuth callback secrets from logs.
Validation: affected Go packages pass; frontend typecheck, changed-file lint, and 111 tests pass. Security enrollment regressions pass on SQLite 3.50.4, MySQL 8.0.46, and PostgreSQL 16.15. Full frontend lint has pre-existing errors outside the changed files.
Move account security settings into a dedicated page and add token status, rotation, revocation, and access history.
Store audit events with role snapshots and JSON metadata, add audit.read authorization and an independent audit page, and upgrade the ClickHouse driver to v2.46.0.
Model-name post-processing is rebuilt around an explicit trailing
@key:value modifier syntax (thinking/effort/temperature/topp) that
overrides request fields, survives model mapping, and records
conversion diagnostics on the consume log.
- Legacy naked aliases (-thinking, -nothinking, -thinking-<budget>,
effort tails) now parse only for positively matched families
(gpt-*/o-series, claude-*, gemini-*, incl. vendor/ namespaces);
names like qwen-max stay opaque. EffortTailModelIDs remains the
escape hatch for real in-family IDs such as gpt-5.1-codex-max.
- Billing identity resolves once in ModelPriceHelper via a ladder:
configured request name first (legacy wildcard entries intact), then
canonical billing names rebuilt from parsed intent
(base@effort:E@thinking:S, then base@thinking:S; order, duplicates,
and budget values are irrelevant; temperature/topp never priced),
then base. Routing and token limits fall back through
RoutingMatchModelName; pricing lookups stay wildcard-only.
- Pass-through stays byte-identical: modifiers and aliases are neither
parsed nor validated there and forward verbatim for the upstream
(or a chained gateway) to interpret.
- Unknown modifier keys and invalid known-key values are rejected with
400; models whose real names contain @tag:value are exempted via the
thinking-suffix blacklist, which now supports re:-prefixed Go regex
entries.
- Claude reasoning render coerces unsupported combinations (disable,
adaptive, budgets) with warning diagnostics instead of erroring;
native-protocol requests without host syntax pass through untouched.
BREAKING(openrouter): drop the host-invented "-thinking" model-name
alias (added in 4f6d16e36) that trimmed any *-thinking model on
OpenRouter channels and injected reasoning.enabled. It matched too
broadly and mangled real model IDs such as kimi-k2-thinking.
Migration: use some-model@thinking:on, or keep the old public name via
a channel model mapping {"some-model-thinking": "some-model@thinking:on"}.
Claude/Gemini family aliases (incl. anthropic/claude-*-thinking) keep
working via the family whitelist.
* fix: reduce public bootstrap requests and revalidate content
* fix(controller): use a weak ETag for revalidated public JSON
/api is gzip-compressed by middleware that runs after the handler returns,
and the validator is computed over the uncompressed body. The compressed and
identity forms of one payload therefore share a validator, which a strong ETag
must not do -- it asserts byte-for-byte equality across representations
(RFC 9110 8.8.1). Serve W/ instead.
Weak comparison ignores W/ on both operands, so etagMatches now strips it from
the served validator as well as from each candidate. Stripping only the
candidate would make a weak served validator match nothing and silently
disable every 304.
Vary: Accept-Encoding stays. Weakening the validator makes revalidation
correct, but it does not separate the two encodings in a shared cache.
* fix(test): align response cookie helper name
* fix(auth): revalidate stale route sessions
* Update web/src/features/about/api.ts
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* test: remove newly added PR tests
---------
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Marketplace install/upgrade on a factory-served plugin actually created
a permanent override shadowing every future built-in release. The card
now shows an informational "Updates with the system" badge instead of
the action, while keeping the built-in vs marketplace version line and
the upgradable state badge visible. Deliberate overrides are untouched:
upload and marketplace actions on overridden or third-party plugins
behave as before, and the plugins table now hints when an override
lags behind the shipped built-in version so operators know deleting it
restores the newer factory plugin.