Skip to content

release#234

Merged
ding113 merged 16 commits intomainfrom
dev
Nov 28, 2025
Merged

release#234
ding113 merged 16 commits intomainfrom
dev

Conversation

@ding113
Copy link
Owner

@ding113 ding113 commented Nov 28, 2025

Summary

Release PR consolidating multiple features and bug fixes since the last release.

Changes

Features

  • Error Response Override - Added ability to configure custom response body and status code for error rules, allowing fine-grained control over error responses returned to clients
  • Chart Visualization Modes - Added Overlay and Stacked display modes for dashboard statistics charts
  • Environment Loading - Improved drizzle.config.ts to follow Next.js env file priority order (.env.development.local > .env.local > .env.development > .env)

Bug Fixes

Internationalization

  • Optimized navigation translations across all locales (en, ja, ru, zh-CN, zh-TW)
  • Added translations for new error override feature

Database

  • New migration 0021_broad_black_panther.sql adding override_response (jsonb) and override_status_code (integer) columns to error_rules table

Files Changed

  • src/app/v1/_lib/proxy/error-handler.ts - Error override application logic
  • src/app/[locale]/settings/error-rules/ - UI for error override configuration
  • src/lib/error-override-validator.ts - Override response validation
  • src/lib/api/action-adapter-openapi.ts - API adapter fix
  • src/lib/availability/availability-service.ts - Availability monitoring fix
  • src/drizzle/schema.ts - Schema updates for error override fields

Testing

  • Manual testing performed
  • Database migration tested
  • No breaking changes

🤖 Generated with Claude Code

ding113 and others added 16 commits November 28, 2025 00:00
English:
- Dashboard: Quota Management→Quotas, User Management→Users, Documentation→Docs
- Settings: Configuration→Config, Sensitive Words→Filters, Client Update Reminder→Updates, Data Management→Data, API Documentation→API Docs, Error Rules→Errors

Russian:
- Dashboard: Документация→Доки
- Settings: Конфигурация→Конфиг, Прайс-лист→Цены, Чувствительные слова→Фильтры, Напоминание об обновлении→Обновления, Управление данными→Данные, API документация→API док., Правила ошибок→Ошибки, Обратная связь→Отзывы

Japanese:
- Dashboard: ダッシュボード→ホーム, ユーザー管理→ユーザー, ドキュメント→ドキュ, システム設定→設定
- Settings: プロバイダー→供給元, センシティブワード→フィルター, クライアント更新リマインダー→更新通知, データ管理→データ, APIドキュメント→API文書, エラールール→エラー, フィードバック→報告
修复正则表达式以同时匹配 "tokens...maximum" 和 "maximum...tokens" 两种格式。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
fix: 改进 prompt_limit 错误规则的正则匹配
Visual presentation modes:

1. Overlay (对比模式)
   - 关注点: 个体差异 ("谁更强")
   - 逻辑: 独立渲染,基准线均为 0
   - 用途: 数值直接对比 (e.g., User A vs User B)

2. Stacked (堆叠模式)
   - 关注点: 整体构成 ("整体怎样")
   - 逻辑: 累加渲染,后续层基于前一层
   - 用途: 总量及占比分析 (e.g., Total Spend composition)
Add ability to override error responses and status codes when error rules match:
- New DB fields: override_response (JSONB) and override_status_code
- Runtime override logic in error-handler with validation (400-599 range)
- New validator for Claude API error format with 10KB size limit
- Frontend: override section component with real-time JSON validation
- Frontend: error rule tester to preview override behavior
- Support empty message fallback to original error
- Backward compatible: no behavior change without override config

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
根本原因:前端传递小数形式的 bucketSizeMinutes(如 0.25 表示 15 秒),
但后端使用 parseInt() 解析,导致 0.25 被转换为 0,
在除法运算中产生 Infinity,最终导致 Invalid Date 错误。

修复:
- API 路由:使用 parseFloat 代替 parseInt 解析 bucketSizeMinutes
- 可用性服务:增加最小值保护(0.25 分钟 = 15 秒)防止除零错误

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…lose #230

The createActionRoute function was passing the entire request body object
as a single argument to Server Actions. This broke actions that expect
positional parameters (e.g., `getUserStatistics(timeRange)` receiving
`{ timeRange: "hour" }` instead of `"hour"`).

The fix extracts parameters from the request body based on the schema
keys and passes them as positional arguments to match the action
function signatures.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Change multi-parameter case to pass entire body object
- Fixes #230 for single-param actions (e.g., getUserStatistics)
- Preserves compatibility for editUser/editKey/editProvider signatures
- Add Number.isNaN check in route.ts to handle invalid parseFloat input
- Add Number.isNaN check in availability-service.ts as defense-in-depth
- Fixes edge case where Math.max(0.25, NaN) returns NaN, causing Invalid Date error
…id-date

Fix #227: 修复可用性监控 15 分钟时间范围的 Invalid Date 错误
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ding113, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a significant new capability by allowing administrators to configure custom error overriding rules. This feature enables the system to intercept specific upstream error messages and return tailored, user-friendly responses and HTTP status codes to clients, while still logging the original detailed errors for debugging. Complementary improvements include UI/UX refinements, better data visualization options in the dashboard, and several backend stability enhancements.

Highlights

  • Error Overriding Feature: Introduced the ability to define custom error override responses (JSON) and HTTP status codes for specific error messages, enhancing control over API error handling.
  • Error Rule Tester: Added a new UI component and backend action to interactively test error rules, simulating how messages are matched and how overrides would be applied at runtime, including warnings for misconfigurations.
  • Database Schema Update: The error_rules table now includes override_response (JSONB) and override_status_code (integer) columns to store the new override configurations.
  • Internationalization (i18n) Updates: Updated localization files across English, Japanese, Russian, Simplified Chinese, and Traditional Chinese to support the new error override features and to shorten various navigation labels for better UX.
  • Dashboard Chart Enhancements: Added a 'chart mode' toggle (overlay/stacked) for user statistics charts, allowing different visualizations of data, and improved sorting for overlay mode.
  • API Action Adapter Improvement: The API action adapter was refined to correctly pass schema parameters as positional arguments to server actions, supporting more flexible function signatures.
  • Availability Monitoring Fix: Resolved an 'Invalid Date' error in availability monitoring when selecting a 15-minute time range and improved bucketSizeMinutes parsing to handle float values and ensure a minimum bucket size.
  • Environment Variable Loading: Updated drizzle.config.ts to load environment variables following Next.js priority order, ensuring consistent configuration.
  • Robust Request ID Extraction: Enhanced the error handling mechanism to more intelligently extract request_id from various nested JSON structures, text patterns, and response headers within upstream errors.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ding113 ding113 added size/XL Extra Large PR (> 1000 lines) enhancement New feature or request labels Nov 28, 2025
@ding113
Copy link
Owner Author

ding113 commented Nov 28, 2025

📊 PR Size Analysis

This PR is XL with 3,502 lines changed across 33 files.

Large PRs are harder to review and more likely to introduce bugs.

🔀 Suggested Split:

Based on the changes, this PR could be split into:

  1. PR 1: Error Response Override Feature (~1,500 lines)

    • src/app/v1/_lib/proxy/error-handler.ts
    • src/app/v1/_lib/proxy/errors.ts
    • src/app/v1/_lib/proxy/responses.ts
    • src/app/[locale]/settings/error-rules/ (all components)
    • src/lib/error-override-validator.ts
    • src/lib/error-rule-detector.ts
    • src/actions/error-rules.ts
    • src/repository/error-rules.ts
    • src/drizzle/schema.ts (error_rules changes)
    • drizzle/0021_broad_black_panther.sql
    • Related i18n message changes
  2. PR 2: Chart Visualization Modes (~200 lines)

    • src/app/[locale]/dashboard/_components/statistics/chart.tsx
    • Related i18n message changes
  3. PR 3: Bug Fixes (~150 lines)

  4. PR 4: Configuration & Infrastructure (~50 lines)

    • drizzle.config.ts - Environment loading improvement
    • src/app/[locale]/settings/data/_components/database-import.tsx
    • CHANGELOG.md

Why Split?

  • Easier to review - reviewers can focus on one concern at a time
  • Faster CI feedback - smaller changes run through CI quicker
  • Easier to revert if needed - isolate issues to specific changes
  • Better git history - clear separation of features and fixes
  • Independent testing - each feature can be verified separately

Note on Generated Files

The drizzle/meta/0021_snapshot.json (~1,600 lines) is auto-generated and doesn't need manual review, but the underlying schema changes should still be reviewed carefully.


🤖 Automated analysis by Claude AI

@ding113
Copy link
Owner Author

ding113 commented Nov 28, 2025

🔒 Security Scan Results

No security vulnerabilities detected

This PR has been scanned against OWASP Top 10, CWE Top 25, and common security anti-patterns. No security issues were identified in the code changes.

📋 OWASP Top 10 Coverage

  • A01: Injection - Clean

    • SQL queries use Drizzle ORM with parameterized queries (no raw SQL concatenation)
    • Regex patterns validated with safe-regex library to prevent ReDoS attacks
    • Input validation present for all user-controlled data
  • A02: Broken Authentication - Clean

    • Admin-only endpoints properly protected with getSession() and role checks
    • No hardcoded credentials detected
  • A03: Sensitive Data Exposure - Clean

    • No sensitive data logged
    • Error messages properly sanitized before returning to clients
  • A04: XML External Entities - N/A (no XML parsing)

  • A05: Broken Access Control - Clean

    • All server actions properly validate admin role before execution
    • Authorization checks present: if (!session || session.user.role !== "admin")
  • A06: Security Misconfiguration - Clean

    • Override status code range validated (400-599) with runtime guards
    • Error override response JSON structure validated before use
    • 10KB size limit enforced on override response body
  • A07: XSS - Clean

    • React components use JSX expressions (auto-escaped)
    • No dangerouslySetInnerHTML with user input
  • A08: Insecure Deserialization - Clean

    • JSON parsing includes structure validation via validateErrorOverrideResponse()
    • Malformed JSON data sanitized at repository layer via sanitizeOverrideResponse()
  • A09: Known Vulnerabilities - Clean (no new dependencies added)

  • A10: Logging & Monitoring - Clean

    • Error override actions properly logged with user context

🛡️ Security Features Implemented

This PR actually improves security posture by:

  1. ReDoS Protection: Uses safe-regex library to validate regex patterns before compilation
  2. Input Validation: Override response must match strict Claude API error format
  3. Size Limits: 10KB maximum for override response body prevents memory exhaustion
  4. Status Code Validation: Runtime guards ensure only valid HTTP error codes (400-599)
  5. Defense in Depth: Double validation at both rule loading and response time
  6. Authorization: All error rule management endpoints require admin role

📝 Code Quality Observations

  • Environment variable loading order change in drizzle.config.ts follows Next.js conventions (not a security issue)
  • All database operations use Drizzle ORM's safe query building (no injection vectors)
  • Frontend components properly escape user input via React's JSX

✅ Security Posture: Strong

The error override feature is well-designed with multiple security layers. No action required before merge.


🤖 Automated security scan by Claude AI - OWASP Top 10 & CWE coverage

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant new feature for error handling, allowing custom override responses and status codes for matched error rules. This includes a new UI for configuration and a tester for validation. Additionally, there are several UI/UX improvements, such as making navigation labels more concise, adding a stacked/overlay mode to charts, and fixing a bug in the availability monitoring chart. However, I've identified a critical regression in the API action adapter (src/lib/api/action-adapter-openapi.ts) that incorrectly handles single-argument server actions, which could break existing functionality. My review includes a detailed explanation and a suggested fix for this issue.

Comment on lines +231 to +252
// 如果 requestSchema 是对象类型,提取 keys 作为参数顺序
let args: unknown[];
if (requestSchema instanceof z.ZodObject) {
const schemaShape = requestSchema.shape;
const keys = Object.keys(schemaShape);
if (keys.length === 0) {
// 没有参数
args = [];
} else if (keys.length === 1) {
// 单个参数,直接传递值
args = [body[keys[0] as keyof typeof body]];
} else {
// 多个参数场景 - 保持原有行为传递整个 body 对象
// 因为存在 editUser(userId, data) 这类签名,无法从 schema 区分
args = [body];
}
} else {
// 非对象 schema,直接传递整个 body
args = [body];
}

const rawResult = await action(...args);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The new logic for handling single-parameter server actions appears to be incorrect. The else if (keys.length === 1) block unwraps the single property from the request body, which will break actions that expect a single object as their parameter (e.g., myAction(input: { message: string })). For instance, the newly added testErrorRuleAction in this same pull request would be called with a string argument instead of the expected object, causing a runtime error. The previous behavior of passing the entire body object was more robust for this common case.

// If requestSchema is an object type, determine arguments
let args: unknown[];
if (requestSchema instanceof z.ZodObject) {
  const keys = Object.keys(requestSchema.shape);
  if (keys.length === 0) {
    // Handle actions with no parameters
    args = [];
  } else {
    // For actions with one or more parameters, pass the entire body object.
    // This is safer and supports both `action({ a, b })` and actions that
    // might destructure a single object argument.
    args = [body];
  }
} else {
  // Non-object schema, pass the entire body as a single argument
  args = [body];
}

const rawResult = await action(...args);

Copy link
Owner Author

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Documentation Review

📊 Issues Summary

  • Critical (🔴): 1 - Must fix before merge
  • High (🟠): 0 - Should fix before merge
  • Medium (🟡): 0 - Consider addressing
  • Low (🟢): 0 - Optional improvements

⚡ Priority Fixes

🔴 Missing Historical Records in CHANGELOG.md

This PR removes 9 previously documented bug fixes from the [Unreleased] section without preserving them:

  • #220: Fix session binding not updating after provider failover
  • #219: Fix provider availability monitoring page sorting order
  • #216: Multiple fixes (JSONB field name error, response validation, login redirect, translations, DialogContent width)
  • #210: Fix model test disclaimer display order
  • #207: Fix provider statistics, group settings persistence

Impact: Historical changelog entries are permanently lost. Users and contributors reviewing the changelog will not see these fixes documented.

Suggested Fix: Either:

  1. Create a versioned release section (e.g., ## [1.x.x] - 2024-11-28) and move these fixes there before removing them from [Unreleased]
  2. Keep these entries in the [Unreleased] section alongside the new fixes (#231, #232)

Reference: Keep a Changelog recommends maintaining all notable changes until they are released under a version tag.

📋 Review Coverage

  • Technical accuracy - No issues
  • Completeness - 1 issue (missing historical entries)
  • Code examples - N/A
  • Links and references - No issues
  • Clarity and organization - No issues

💡 General Observations

The PR description is well-structured and comprehensive, but the CHANGELOG.md changes contradict the stated goal of "consolidating multiple features and bug fixes since the last release" - instead, it removes documentation of previous fixes. Consider:

  1. If this is a release PR, add a versioned section header before clearing [Unreleased]
  2. The features mentioned in the PR description (Error Response Override, Chart Visualization Modes) should also be added to CHANGELOG.md under ### Added

🤖 Automated docs review by Claude AI

@ding113
Copy link
Owner Author

ding113 commented Nov 28, 2025

📝 Documentation Review

📊 Issues Summary

  • Critical (🔴): 1 - Must fix before merge
  • High (🟠): 0 - Should fix before merge
  • Medium (🟡): 0 - Consider addressing
  • Low (🟢): 0 - Optional improvements

⚡ Priority Fixes

🔴 Missing Historical Records in CHANGELOG.md

This PR removes 9 previously documented bug fixes from the [Unreleased] section without preserving them:

Impact: Historical changelog entries are permanently lost. Users and contributors reviewing the changelog will not see these fixes documented.

Suggested Fix: Either:

  1. Create a versioned release section (e.g., ## [1.x.x] - 2024-11-28) and move these fixes there before removing them from [Unreleased]
  2. Keep these entries in the [Unreleased] section alongside the new fixes (Fix #227: 修复可用性监控 15 分钟时间范围的 Invalid Date 错误 #231, Fix #230: API action adapter should pass schema params as positional args #232)

Reference: Keep a Changelog recommends maintaining all notable changes until they are released under a version tag.

📋 Review Coverage

  • Technical accuracy - No issues
  • Completeness - 1 issue (missing historical entries)
  • Code examples - N/A
  • Links and references - No issues
  • Clarity and organization - No issues

💡 General Observations

The PR description is well-structured and comprehensive, but the CHANGELOG.md changes contradict the stated goal of "consolidating multiple features and bug fixes since the last release" - instead, it removes documentation of previous fixes. Consider:

  1. If this is a release PR, add a versioned section header before clearing [Unreleased]
  2. The features mentioned in the PR description (Error Response Override, Chart Visualization Modes) should also be added to CHANGELOG.md under ### Added

🤖 Automated docs review by Claude AI

Copy link
Owner Author

@ding113 ding113 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📋 Code Review Summary

This is a release PR consolidating multiple features including Error Response Override, Chart Visualization Modes, and bug fixes for API action adapter and availability monitoring. The code quality is generally good with proper validation and error handling.

🔍 Issues Found

  • Critical (🔴): 0 issues
  • High (🟠): 1 issue
  • Medium (🟡): 2 issues
  • Low (🟢): 1 issue

🎯 Priority Actions

  1. [🟠 High] action-adapter-openapi.ts:233 - The single-parameter extraction logic using Object.keys(schemaShape) relies on property ordering which, while practically stable in V8, is not guaranteed by the JavaScript specification. Consider explicitly sorting keys or documenting the assumption.

  2. [🟡 Medium] drizzle.config.ts:4-8 - The new env file loading loop doesn't use override: false option for dotenv.config(), meaning later files will NOT override earlier ones. The comment says "priority order" but the implementation does the opposite - first match wins, so .env.development.local takes priority only if loaded first AND subsequent loads don't override. Consider adding override: true to reverse the effective priority.

  3. [🟡 Medium] availability-service.ts:182-187 - The NaN handling uses Number.isNaN() which is correct, but the minimum bucket size of 0.25 minutes (15 seconds) is very small. With high-volume data, this could create thousands of buckets causing performance issues. Consider a larger minimum like 1 minute.

  4. [🟢 Low] error-override-validator.ts:78 - The isValidErrorOverrideResponse type guard function duplicates validation logic by calling validateErrorOverrideResponse. This is fine but could note in comments that the two functions share logic.

💡 General Observations

  • Good use of validation at multiple layers (repository, detector, action) for the error override feature
  • The atomic cache replacement pattern in ErrorRuleDetector.reload() is well implemented
  • Proper ReDoS protection with safe-regex is maintained
  • Translation keys are consistently added across all locales

🤖 Automated review by Claude AI - focused on identifying issues for improvement


// 如果 requestSchema 是对象类型,提取 keys 作为参数顺序
let args: unknown[];
if (requestSchema instanceof z.ZodObject) {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 High: Object.keys() does not guarantee property order

Why this is a problem: While V8 maintains insertion order for string keys, the JS spec does not guarantee ordering. This could cause parameter order mismatch in edge cases.

Suggested fix:

const keys = Object.keys(schemaShape).sort(); // Explicitly sort for deterministic order

const rawBucketSize =
explicitBucketSize ?? determineOptimalBucketSize(requests.length, timeRangeMinutes);
const bucketSizeMinutes = Number.isNaN(rawBucketSize)
? determineOptimalBucketSize(requests.length, timeRangeMinutes)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium: Minimum bucket size of 0.25 minutes may cause performance issues

Why this is a problem: With 15-second buckets on high-volume data, this could create thousands of buckets causing memory and CPU performance issues during aggregation.

Suggested fix:

const bucketSizeMinutes = Number.isNaN(rawBucketSize)
  ? determineOptimalBucketSize(requests.length, timeRangeMinutes)
  : Math.max(1, rawBucketSize); // Use 1 minute as minimum for safety

// Priority: .env.development.local > .env.local > .env.development > .env
const envFiles = [".env.development.local", ".env.local", ".env.development", ".env"];
for (const envFile of envFiles) {
config({ path: envFile });
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium: dotenv config() priority order is inverted from comment

Why this is a problem: The comment says "Priority: .env.development.local > .env.local > ..." but dotenv.config() by default does NOT override already-set variables. So loading in this order means .env.development.local is loaded first and its values are set, then subsequent files cannot override them. The actual priority is first-file-wins, which matches Next.js priority.

However, if DSN is already set in an earlier file, later files won't override it. Consider whether this is intentional.

Suggested clarification: Update the comment to clarify the "first wins" behavior, or use override: true if you want later files to take precedence:

for (const envFile of envFiles) {
  config({ path: envFile, override: false }); // First file wins (Next.js style)
}

@ding113 ding113 merged commit 08af74e into main Nov 28, 2025
18 checks passed
ding113 pushed a commit that referenced this pull request Nov 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size/XL Extra Large PR (> 1000 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: API接口获取统计数据失败 Bug: 可用性监控渲染失败

2 participants

Comments