- 15 Apr, 2026 1 commit
-
-
erio authored
Replace dead EventSource variable with AbortController to enable cancelling fetch streams. Remove close-button disable during connecting status so users can dismiss the dialog at any time.
-
- 14 Apr, 2026 32 commits
-
-
erio authored
- Fix flaky WebSocket passthrough test: allow StatusNormalClosure after client close instead of requiring NoError (race condition fix) - Fix ratelimit 401 test: use PlatformOpenAI instead of PlatformGemini for OAuth token cache invalidation scenario (more accurate) - Add usageLoadQueue: Anthropic OAuth/setup-token accounts sharing the same proxy exit are serialized with 1-2s jitter to prevent upstream 429 - AccountUsageCell: add module-level usage cache (5min TTL), unmounted safety guard, and integrate enqueueUsageRequest for throttled fetching
-
erio authored
Extract repeated badge template (SVG icon + current/max display) into a reusable CapacityBadge component. Reduces AccountCapacityCell from ~300 lines to ~180 lines with identical behavior.
-
erio authored
Backend: - gateway_handler: pass subject.UserID instead of int64(0) for user-level routing - setting_handler: add missing BalanceLowNotifyRechargeURL to UpdateSettings response - openai_gateway_service: use applyAccountStatsCost for account stats pricing integration - embed_on: add local file override (data/public/) for embedded frontend assets Frontend: - useTableSelection: add batchUpdate method for batch operations - AccountsView: virtual scrolling params, Set-based isSelected, swipe virtualization - ProxiesView: add batchUpdate to selection and swipe-select - BulkEditAccountModal: fix submit handler to prevent event object as argument - SettingsView: move payload construction outside try block - i18n: add general translation keys (saved, deleted, view, validation, allowUserRefund) - api/client: reorder error fields for consistency - stores/payment: clarify pollOrderStatus JSDoc
-
erio authored
allow_user_refund: - Add allow_user_refund field to PaymentProviderInstance ent schema - Migration 103: ALTER TABLE payment_provider_instances ADD COLUMN - Cascade logic: disabling refund_enabled auto-disables allow_user_refund - User refund validation: check provider instance allows user refund - Admin refund validation: check provider instance allows admin refund - Subscription refund: deduct days on refund, rollback on failure - New endpoint: GET /payment/orders/refund-eligible-providers - Frontend: ToggleSwitch in ProviderCard/Dialog, cascade in SettingsView Wildcard matching: - Change findPricingForModel from "longest prefix wins" to "config order priority (first match wins)", aligning with channel service behavior
-
erio authored
- QuotaLimit changed to *int64 (null=unlimited, >0=limited) - Add reset-usage endpoint (POST /admin/settings/web-search-emulation/reset-usage) - Show quota usage in header always (collapsed and expanded) - Add reset quota button in expanded provider view - Quota input: empty=unlimited with ∞ placeholder, must be >0 if set - Add email verification hint on balance notify card
-
erio authored
Security (HIGH): - Normalize all Redis cache keys to lowercase (verifyCode, passwordReset) - Fix verify code TTL renewal on failed attempts: use remaining TTL via ExpiresAt field instead of resetting to full 15-minute window - Add 3 missing fields to diffSettings audit log (promo_code, invitation_code, custom_endpoints) Code quality (MEDIUM): - Extract filterVerifiedEmails shared helper (balance_notify_service.go) - Add Pricing array non-empty validation for channel pricing rules - Add platform token semantics comment in gateway_service.go - Complete validatePlanPatch test coverage (+10 test cases) - Replace string types with QuotaThresholdType/QuotaResetMode across frontend - Remove duplicate getPlatformTextColor/getRateBadgeClass in ChannelsView - Return EMAIL_NOT_FOUND error on RemoveNotifyEmail miss UI improvements: - Reorder cost tooltip: user billing above separator, account billing below - Add NaN guard to accountBilled function - Move timezone selector inline into reset-mode row (no longer standalone)
-
erio authored
M5: New composable frontend/src/composables/useQuotaNotifyState.ts - Replaces 9 individual refs in both Create/Edit modals with reactive state - Provides loadFromExtra/writeToExtra/reset helpers - Eliminates ~120 lines of duplicated code across the two modals H14: Vue file length violations fixed - AdminPaymentPlansView.vue: 325 → 183 lines (extracted PlanEditDialog.vue) - QuotaLimitCard.vue: 327 → 268 lines (extracted QuotaDimensionRow.vue) - PlanEditDialog.vue: 181 lines (new, plan create/edit form) - QuotaDimensionRow.vue: 108 lines (new, single quota dimension row)
-
erio authored
H5: diffSettings now tracks 5 balance/quota notify fields in audit log M15: log.Printf audit log migrated to slog.Info, removed "log" import M14: New frontend/src/constants/account.ts with shared constants QuotaNotifyToggle.vue uses QUOTA_THRESHOLD_TYPE_FIXED/PERCENTAGE L2: UsageTable.vue uses BILLING_MODE_TOKEN/IMAGE from billingMode.ts -
erio authored
fix: batch 1 audit fixes — quota SQL fixed mode, public recharge URL, WebSearch bool fallback, UpdatePlan validation H1: incrementUsageBillingAccountQuota now uses shared dailyExpiredExpr/weeklyExpiredExpr constants (supporting fixed reset mode) instead of hardcoded '24 hours'/'168 hours' H4: public settings endpoint now maps balance_low_notify_recharge_url H6: GetWebSearchEmulationMode tolerates legacy bool values (true→enabled) H7: UpdatePlan validates non-nil patch fields (rejects negative price, empty name, etc.) H8: UsageTable accountBilled() helper with total_cost ?? 0 null guard H9: AdminUsageLog TS type adds channel_id + billing_tier M2: account.go "fixed" literals replaced with thresholdTypeFixed constant M13: SystemSettings TS type adds web_search_emulation_enabled UI: QuotaLimitCard title labels now use flex-1 to align with flex-1 input boxes -
erio authored
- EditAccountModal width changed from "normal" to "wide" (match CreateAccountModal) - CreateAccountModal now passes all quota notify props to QuotaLimitCard - QuotaLimitCard: when global notify disabled, hide title row, input takes full width - Quota alert email: show remaining quota + threshold (fixed/$, percentage/%) instead of usage trigger point
-
erio authored
-
erio authored
Threshold now represents remaining quota instead of usage amount: - Fixed ($): threshold=400, limit=1000 → alert when remaining drops to $400 (i.e., usage reaches $600) - Percentage (%): threshold=30%, limit=1000 → alert when remaining drops to 30% (i.e., usage reaches $700) Also: - Rename 告警阈值 → 提醒阈值 in i18n - Widen type dropdown to w-16 for proper $ / % display
-
erio authored
Move QuotaNotifyToggle to the same row as the limit $ input for all three dimensions (daily/weekly/total), significantly reducing card height.
-
erio authored
- QuotaLimitCard: add collapse/expand toggle (chevron icon + click header) - QuotaNotifyToggle: show $ or % suffix in threshold input - Reduce vertical spacing between reset mode hint and notify toggle
-
erio authored
- QuotaNotifyToggle: add $ or % suffix to threshold input based on type - QuotaLimitCard: combine reset mode and notify toggle on same row to reduce vertical height for daily/weekly sections - Remove redundant ml-4 indentation from QuotaNotifyToggle
-
erio authored
- "默认(跟随渠道)" → "默认", "Default (follow channel)" → "Default" - Move "follows channel config" info to description text - Reduce select width from w-32 to w-24 in both Edit and Create modals
-
erio authored
QuotaLimitCard now requires quotaNotifyGlobalEnabled prop to control visibility of QuotaNotifyToggle components. When the global account quota notification is disabled in admin settings, per-account threshold toggles are hidden in both Edit and Create account modals.
-
knowsky404 authored
-
erio authored
Backend fixes: - Fix balance notify ignoring percentage threshold type (was treating percentage value as fixed USD amount) - Remove dead code parseJSONStringArray - Add ImageOutputTokens to tryModelFilePricing calculation - Unify zero-value check: cost == 0 → cost <= 0 in calculateTokenStatsCost - Use MarshalNotifyEmails instead of json.Marshal for consistency - Rename quotaDim.oldUsed → currentUsed for clarity - Extract HTML email templates to const variables (function ≤30 lines) Test fixes: - Rewrite account_websearch_test.go for GetWebSearchEmulationMode tri-state - Add 6 tryModelFilePricing test cases Frontend fixes: - Replace hardcoded '未命名' with i18n key - Extract getBillingModeLabel/getBillingModeBadgeClass to shared utils - Replace inline type with imported NotifyEmailEntry - Pass platform to AccountStats pricing rules via inferRulePlatform() - Add billing mode constants (BILLING_MODE_TOKEN/PER_REQUEST/IMAGE)
-
erio authored
WebSearch tri-state switch: - Account-level web_search_emulation changed from bool to tri-state string: "default" (follow channel) / "enabled" / "disabled" - shouldEmulateWebSearch checks channel config when account is "default" - SQL migration converts old bool values - Frontend select replaces toggle in Edit/CreateAccountModal Account stats pricing: - resolveAccountStatsCost uses upstream model (post-mapping) for matching - Priority: custom rules → model pricing file (when toggle on) → default - Custom rules always configurable, independent of toggle - Account ID field changed to searchable selector filtered by platform - Description updated to reflect new behavior Quota notification cache fix: - CheckAccountQuotaAfterIncrement fetches real-time account from DB - Reconstructs pre-increment usage for accurate threshold crossing detection - New AccountQuotaReader interface (minimal: GetByID only) Usage tooltip: - Per-request/image billing shows per-request price instead of $0 token price - Token billing continues to show input/output price per million tokens
-
erio authored
- Add "verify" button next to saved unverified emails in ProfileBalanceNotifyCard (send code → enter code → verify) - Backend: VerifyAndAddNotifyEmail now marks existing unverified emails as verified instead of returning "already exists" - Inline verification UI with countdown timer and resend button
-
erio authored
- Fix cached balance causing threshold crossing to never trigger: read real-time balance from billingCacheService instead of stale API key auth snapshot - Remove email="" placeholder concept; all emails are user-managed - Only send notifications to verified && non-disabled emails - Frontend: pre-fill user's email in add input when list is empty - Remove FilterEnabledEmails/IsPrimaryDisabled helpers (no longer needed)
-
erio authored
- Change balance_notify_extra_emails and account_quota_notify_emails from []string to []NotifyEmailEntry{email, disabled, verified} - Add per-email enable/disable toggle for both user and admin notifications - Add PUT /user/notify-email/toggle API endpoint - Fix critical bug: API key auth cache snapshot missing balance notify fields (Email, Username, BalanceNotifyEnabled, etc.), causing notifications to never fire on cached request paths - Bump cache snapshot version 3→4 to invalidate stale entries - Add SQL migration 104 to convert old format data - Backward compatible: parseNotifyEmails auto-detects old/new format - User balance notify: max 3 emails (primary + 2 extra) - Admin quota notify: unlimited emails, each with toggle -
erio authored
Replace blur-based auto-save with an explicit Save button so users know when their threshold is persisted. Shows success toast on save.
-
erio authored
-
erio authored
- Show system default threshold as placeholder in custom threshold input - Display user's primary email with "Primary" badge - Support adding multiple pending emails before verification - Each pending email has independent send/verify/resend flow - Expose balance_low_notify_threshold in PublicSettings API - Clean up timers on unmount to prevent leaks
-
erio authored
- Fix GetByKeyForAuth missing user.FieldEmail and user.FieldUsername (notifications sent to empty address) - Guard against empty email in collectBalanceNotifyRecipients - Remove non-atomic TotalRecharged read-modify-write in admin balance adjustment - HTML-escape userName/siteName/accountName in notification email templates - Fix timer leak in ProfileBalanceNotifyCard (add onUnmounted cleanup) - Add warning log on websearch proxy URL resolution failure
-
erio authored
- Add global toggle for account quota notification in admin settings - Add percentage-based threshold type for per-account quota alerts - Hide balance notify card on user profile when global toggle is off - Expose balance_low_notify_enabled and account_quota_notify_enabled in PublicSettings - Add threshold type (fixed/percentage) to QuotaNotifyToggle with $ / % switcher
-
erio authored
- API Key show/copy buttons moved inside input field (inline icons) - Proxy selector and test button on same row to save vertical space - Test opens a dialog modal instead of inline display - Hide all websearch config in channels/accounts when global toggle is off
-
erio authored
- Fix accountCost calculation in finalizePostUsageBilling to match postUsageBilling (always multiply by AccountRateMultiplier) - Use strings.EqualFold for email dedup in collectBalanceNotifyRecipients - Extract CheckAccountQuotaAfterIncrement into smaller functions: buildQuotaDims + asyncSendQuotaAlert (< 30 lines each) - Add "not splittable" comments for HTML template functions - Extract QuotaNotifyToggle.vue sub-component to reduce QuotaLimitCard.vue from 404 to 339 lines
-
erio authored
- User balance low notification: email alert when balance drops below configurable threshold (user email + verified extra emails) - Account quota notification: broadcast email to admin-configured recipients when daily/weekly/total quota usage exceeds alert threshold - Admin settings: global enable/disable, default threshold, quota notification email list (Email Settings tab) - User profile: enable/disable, custom threshold, add/remove extra notification emails with verification code flow - Account quota: per-dimension alert toggle and threshold in quota control card - Trigger logic: first-crossing only (old >= threshold && new < threshold for balance; old < threshold && new >= threshold for quota), naturally prevents duplicate notifications without Redis dedup
-
erio authored
Inject web search capability for Claude Console (API Key) accounts that don't natively support Anthropic's web_search tool. When a pure web_search request is detected, the gateway calls Brave Search or Tavily API directly and constructs an Anthropic-protocol-compliant SSE/JSON response without forwarding to upstream. Backend: - New `pkg/websearch/` SDK: Brave and Tavily provider implementations with io.LimitReader, proxy support, and Redis-based quota tracking (Lua atomic INCR + TTL, DECR rollback on failure) - Global config via `settings.web_search_emulation_config` (JSON) with in-process cache + singleflight, input validation, API key merge on save, and sanitized API responses - Channel-level toggle via `channels.features_config` JSONB column (DB migration 101) - Account-level toggle via `accounts.extra.web_search_emulation` - Request interception in `Forward()` with SSE streaming response construction using json.Marshal (no manual string concatenation) - Manager hot-reload: `RebuildWebSearchManager()` called on config save and startup via `SetWebSearchRedisClient()` - 70 unit tests covering providers, manager, config validation, sanitization, tool detection, query extraction, and response building Frontend: - Settings → Gateway tab: Web Search Emulation config card with global toggle, provider list (add/remove, API key, priority, quota, proxy) - Channels → Anthropic tab: web search emulation toggle with global state linkage (disabled when global off) - Account Create/Edit modals: web search emulation toggle for API Key type with Toggle component - Full i18n coverage (zh + en)
-
- 13 Apr, 2026 2 commits
-
-
knowsky404 authored
-
erio authored
Closes #1607
-
- 12 Apr, 2026 2 commits
-
-
qingyuzhang authored
-
qingyuzhang authored
-
- 11 Apr, 2026 3 commits
-
-
erio authored
Backend: - Split payment_order.go (546→314 lines) into payment_order_lifecycle.go - Replace magic strings with constants in factory, easypay, webhook handler - Add rate limit/validity unit constants in payment_order_lifecycle, payment_service - Fix critical regression: add PaymentEnabled to GetPublicSettings response - Add missing migration 099_fix_migrated_purchase_menu_label_icon.sql Frontend: - Fix StripePopupView.vue: replace `as any` with typed interface, use extractApiErrorMessage - Fix AdminOrderTable.vue: replace hardcoded column labels with i18n t() calls - Fix SubscriptionsView.vue: replace hardcoded Today/Tomorrow with i18n - Extract duplicate statusBadgeClass/canRefund/formatOrderDateTime to orderUtils.ts - Add missing i18n keys: common.today, common.tomorrow, payment.orders.orderType/actions - Remove dead PurchaseSubscriptionView.vue (replaced by PaymentView)
-
erio authored
- Add payment navigation to AppSidebar (user orders + admin payment menu group with collapse) - Add 5 missing nav i18n keys (myOrders, orderManagement, paymentDashboard, paymentConfig, paymentPlans) - Renumber payment migrations 090-100 → 092-102 to avoid conflict with upstream 090/091 - Remove non-payment sora_client_enabled change, restore upstream purchase_subscription fields - Remove extra 'data' from SettingsTab type union
-
erio authored
Add a full payment and subscription system supporting EasyPay (Alipay/WeChat), Stripe, and direct Alipay/WeChat Pay providers with multi-instance load balancing.
-