Skip to content

build: v1.6.1#8

Merged
jasoneri merged 3 commits intomasterfrom
dev
Feb 17, 2026
Merged

build: v1.6.1#8
jasoneri merged 3 commits intomasterfrom
dev

Conversation

@jasoneri
Copy link
Copy Markdown
Owner

@jasoneri jasoneri commented Feb 17, 2026

  • nyc.mn 旧域名已废弃,新域名后缀 xyz
  • win安装自动开防火墙
  • 文档更新内容,例如个人更方便的 Tunnel 方案

Summary by Sourcery

Update viewer navigation, backend configuration, domains, and installer behavior for the v1.6.1 release.

New Features:

  • Add first/last page navigation controls to the page reader and expose them via the UI.
  • Introduce an API endpoint and frontend logic to read and update global backend configuration for the frontend.

Bug Fixes:

  • Ensure macOS bundled uv binary is resolved from the executable directory in the Tauri app.

Enhancements:

  • Improve backend URL initialization precedence to respect server-defined configuration while allowing local overrides.
  • Update Tauri configuration to enable macOS private API features and expose external binaries correctly.
  • Show a clearer success message and behavior when saving global backend settings from the admin UI.

Build:

  • Add Windows installer hooks to automatically open and later remove firewall rules for required ports.
  • Enable Vite dev server proxying for the new /api/config endpoint and allow external hosts during development.

Documentation:

  • Update project homepage, demo links, and assets to the new xyz domain, removing deprecated nyc.mn URLs.
  • Rewrite and expand deployment documentation to emphasize the Cloudflare Tunnel-based personal deployment flow and clarify frontend/backend separation.
  • Clarify Linux.do contribution requirements and update feature guide with newly available UI behaviors.
  • Refresh GitHub presets and release notes to match the new domain and v1.6.1 changes.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Feb 17, 2026

Reviewer's Guide

Adds a global backend URL config API and frontend initialization logic, improves the page reader with first/last page controls, updates Windows installer firewall behavior and Tauri packaging, and refreshes docs/links to the new xyz domain and revised deployment guidance.

Sequence diagram for backend URL initialization via api_config

sequenceDiagram
    actor User
    participant Browser
    participant Frontend_initBackend as Frontend_initBackend
    participant LocalStorage
    participant Backend_api as Backend_api_config
    participant DesktopDetector
    participant EnvConfig

    User->>Browser: Load frontend app
    Browser->>Frontend_initBackend: Call initBackend()

    Frontend_initBackend->>LocalStorage: Get backendUrl
    LocalStorage-->>Frontend_initBackend: localUrl or null
    Frontend_initBackend->>LocalStorage: Get list_bg
    LocalStorage-->>Frontend_initBackend: localBg or null
    note over Frontend_initBackend: If localUrl exists, set _backendUrl
    note over Frontend_initBackend: If localBg exists, set _listBg

    Frontend_initBackend->>Backend_api: GET /api/config
    alt Backend_api returns 200
        Backend_api-->>Frontend_initBackend: { backendUrl, bgGif }
        note over Frontend_initBackend: serverUrl = backendUrl
        alt localUrl is null and backendUrl exists
            Frontend_initBackend->>Frontend_initBackend: _backendUrl = backendUrl
        end
        alt localBg is null and bgGif exists
            Frontend_initBackend->>Frontend_initBackend: _listBg = bgGif
        end
    else Backend_api error
        Backend_api-->>Frontend_initBackend: error
        Frontend_initBackend->>Frontend_initBackend: Log warning
    end

    alt no localUrl and no serverUrl
        Frontend_initBackend->>DesktopDetector: detectDesktopBackendUrl()
        DesktopDetector-->>Frontend_initBackend: desktopUrl or null
        alt desktopUrl exists
            Frontend_initBackend->>Frontend_initBackend: _backendUrl = desktopUrl
        else
            Frontend_initBackend->>EnvConfig: Read import.meta.env.LAN_IP
            EnvConfig-->>Frontend_initBackend: fallbackUrl
            Frontend_initBackend->>Frontend_initBackend: _backendUrl = fallbackUrl
        end
    end

    Frontend_initBackend-->>Browser: Resolved _backendUrl
Loading

Sequence diagram for updating global backend URL via api_config

sequenceDiagram
    actor AdminUser
    participant Browser
    participant Frontend_TabBackend as Frontend_TabBackend
    participant Backend_api as Backend_api_config
    participant RootAuth as Root_auth
    participant TargetBackend as Target_backend
    participant ConfigStore

    AdminUser->>Browser: Open root admin TabBackend
    AdminUser->>Frontend_TabBackend: Enter backendUrl and secret
    AdminUser->>Frontend_TabBackend: Click saveBackend()

    Frontend_TabBackend->>Backend_api: POST /api/config { backendUrl, secret }

    Backend_api->>RootAuth: is_auth_required()
    RootAuth-->>Backend_api: auth_required flag
    alt no secret provided
        Backend_api-->>Frontend_TabBackend: 401 需要密钥
    else secret provided but auth not configured
        Backend_api-->>Frontend_TabBackend: 403 请先设置密钥
    else secret provided and auth configured
        Backend_api->>RootAuth: verify_secret(secret)
        RootAuth-->>Backend_api: valid or invalid
        alt secret invalid
            Backend_api-->>Frontend_TabBackend: 401 密钥验证失败
        else secret valid
            Backend_api->>Backend_api: Normalize backendUrl (trim, strip '/')
            alt backendUrl empty or invalid format
                Backend_api-->>Frontend_TabBackend: 400 地址错误
            else backendUrl valid
                Backend_api->>TargetBackend: GET {backendUrl}/root/
                alt TargetBackend reachable and status < 400
                    TargetBackend-->>Backend_api: 200 OK
                    Backend_api->>ConfigStore: set frontend_backend_url = backendUrl
                    ConfigStore-->>Backend_api: saved
                    Backend_api-->>Frontend_TabBackend: 200 success
                else connection fails or status >= 400
                    TargetBackend-->>Backend_api: error
                    Backend_api-->>Frontend_TabBackend: 502 无法连接目标后端
                end
            end
        end
    end

    alt globalSaved is true in frontend
        Frontend_TabBackend->>Browser: localStorage.removeItem(backendUrl)
        Frontend_TabBackend->>AdminUser: Show toast 全局配置已更新,所有设备刷新后生效
    else globalSaved is false
        Frontend_TabBackend->>Browser: localStorage.setItem(backendUrl)
        Frontend_TabBackend->>AdminUser: Show local-only saved message
    end
Loading

File-Level Changes

Change Details Files
Enhance page reader with clickable page indicator that reveals first/last page navigation buttons.
  • Wrap page indicator text in a clickable container that toggles a button group when slider is hidden and images exist.
  • Add reactive state and methods to toggle the button group and to jump directly to first and last pages, emitting pageChange/showBtnChange consistently.
  • Introduce FirstPage and LastPage SVG icon components, register them in the icon index, and style the new page navigation buttons with fade transitions and disabled states.
frontend/src/components/func/PageReader.vue
frontend/src/icons/FirstPage.vue
frontend/src/icons/LastPage.vue
frontend/src/icons/index.js
Introduce a backend-driven global frontend config endpoint and wire the frontend to consume it when initializing the backend URL and background GIF.
  • Add a new /api/config router with GET/POST handlers that expose and update the persisted frontend backend URL, including input validation, secret-based auth, and reachability checks via httpx.
  • Mount the new api_config_router on the FastAPI app under the /api prefix.
  • Change frontend initBackend() to fetch /api/config, prefer localStorage values when present, and fall back to desktop detection or build-time LAN_IP only if neither local nor server config exist.
  • Update the backend admin "TabBackend" save logic so that when global config is successfully saved, localStorage backendUrl is cleared and the message copy reflects that the change affects all devices.
backend/api/routes/root.py
backend/api/__init__.py
frontend/src/static/store.js
frontend/src/root/TabBackend.vue
frontend/vite.config.js
Improve development and desktop app runtime behavior, including Windows firewall configuration and Tauri packaging paths/features.
  • Add a Vite dev server proxy for /api/config to the backend port, enabling local development against the new config API.
  • Adjust macOS uv binary resolution in the Tauri lib to load uv from the same Contents/MacOS directory as the main executable, which matches externalBin layout.
  • Enable Windows installer post-install/post-uninstall hooks to add and remove a firewall rule allowing inbound TCP on ports 8080 and 12345 via netsh advfirewall.
  • Enable the macos-private-api feature on the Tauri dependency in both workspace and src-tauri Cargo.toml to support macOS-specific behaviors.
frontend/vite.config.js
deploy/tauri/lib/src/paths.rs
deploy/tauri/src-tauri/windows/hooks.nsh
deploy/tauri/Cargo.toml
deploy/tauri/src-tauri/Cargo.toml
Update documentation, presets, and site links to the new xyz domain and refresh deployment/docs content.
  • Switch README, docs theme, and GitHub preset links/images from the deprecated nyc.mn domain to rv.101114105.xyz and related subdomains.
  • Rework the advanced deployment guide to recommend a unified Cloudflare Tunnel-based setup for personal use, then describe a separate front/back deployment path; adjust headings/structure for clarity.
  • Add documentation notes describing the new page reader affordances (e.g., clicking page number to jump to first/last page) and other small UX tips.
  • Loosen and clarify Linux.do community contribution instructions in the feed dialog text.
  • Update GitHub release notes to mention the domain change, Windows firewall behavior, and new tunnel documentation.
README.md
docs/deploy/adv.md
docs/guide/index.md
docs/.vitepress/theme/MyLayout.vue
docs/_github/preset.md
docs/_github/release_notes.md
docs/contribute/feed.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@jasoneri jasoneri merged commit 4869152 into master Feb 17, 2026
4 checks passed
Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • In ApiConfigUpdate the currentBackend field is never used in update_api_config; consider either wiring it into the logic (e.g., for validation or migration) or removing it to avoid confusion about its purpose.
  • In update_api_config after successfully setting frontend_backend_url you don't return any explicit success payload, so clients will receive a null JSON body; consider returning a simple { "success": true } (and possibly the saved URL) for clearer client handling and consistency with other endpoints.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `ApiConfigUpdate` the `currentBackend` field is never used in `update_api_config`; consider either wiring it into the logic (e.g., for validation or migration) or removing it to avoid confusion about its purpose.
- In `update_api_config` after successfully setting `frontend_backend_url` you don't return any explicit success payload, so clients will receive a `null` JSON body; consider returning a simple `{ "success": true }` (and possibly the saved URL) for clearer client handling and consistency with other endpoints.

## Individual Comments

### Comment 1
<location> `backend/api/routes/root.py:76-79` </location>
<code_context>
     whitelist: list[str]


+class ApiConfigUpdate(BaseModel):
+    backendUrl: str | None = None
+    currentBackend: str | None = None
+    secret: str | None = None
+
+
</code_context>

<issue_to_address>
**suggestion:** The `currentBackend` field in `ApiConfigUpdate` is defined but never used in the endpoint logic.

Since only `backendUrl` and `secret` are read in `update_api_config`, consider removing `currentBackend` to keep the model minimal. If you plan to use it later, either wire it into the current logic now or introduce a dedicated DTO when that logic is added.

Suggested implementation:

```python
class ApiConfigUpdate(BaseModel):
    backendUrl: str | None = None
    secret: str | None = None

```

1. Search the codebase for any remaining references to `currentBackend` (e.g. in request bodies, tests, or frontend code) and remove or adjust them accordingly.
2. If this API is consumed externally, consider whether this is a breaking change; if so, update API documentation and any client DTOs to match.
</issue_to_address>

### Comment 2
<location> `backend/api/routes/root.py:154-163` </location>
<code_context>
+@api_config_router.post('/config')
</code_context>

<issue_to_address>
**issue (bug_risk):** Authentication failures against the target backend are treated as connectivity failures, which can mislead users.

The connectivity check currently treats any `r.status_code >= 400` as a network error and returns `"无法连接目标后端"`. For backends that require their own credentials, a 401/403 still proves the URL is reachable, but the message implies a connectivity problem instead of an auth issue. Consider either treating any HTTP response as a successful connectivity check and only handling transport-level failures, or special-casing 401/403 (and possibly other 4xx) with a more accurate error message to avoid confusing users for protected backends.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +76 to +79
class ApiConfigUpdate(BaseModel):
backendUrl: str | None = None
currentBackend: str | None = None
secret: str | None = None
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: The currentBackend field in ApiConfigUpdate is defined but never used in the endpoint logic.

Since only backendUrl and secret are read in update_api_config, consider removing currentBackend to keep the model minimal. If you plan to use it later, either wire it into the current logic now or introduce a dedicated DTO when that logic is added.

Suggested implementation:

class ApiConfigUpdate(BaseModel):
    backendUrl: str | None = None
    secret: str | None = None
  1. Search the codebase for any remaining references to currentBackend (e.g. in request bodies, tests, or frontend code) and remove or adjust them accordingly.
  2. If this API is consumed externally, consider whether this is a breaking change; if so, update API documentation and any client DTOs to match.

Comment on lines +154 to +163
@api_config_router.post('/config')
async def update_api_config(req: ApiConfigUpdate):
if not req.secret:
return JSONResponse({'error': '需要密钥'}, status_code=401)
if not is_auth_required():
return JSONResponse({'error': '请先设置密钥'}, status_code=403)
if not verify_secret(req.secret):
return JSONResponse({'error': '密钥验证失败'}, status_code=401)

target = (req.backendUrl or '').strip().rstrip('/')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): Authentication failures against the target backend are treated as connectivity failures, which can mislead users.

The connectivity check currently treats any r.status_code >= 400 as a network error and returns "无法连接目标后端". For backends that require their own credentials, a 401/403 still proves the URL is reachable, but the message implies a connectivity problem instead of an auth issue. Consider either treating any HTTP response as a successful connectivity check and only handling transport-level failures, or special-casing 401/403 (and possibly other 4xx) with a more accurate error message to avoid confusing users for protected backends.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant