Skip to content

refactor: Release迁移到后端代理, 添加Fork和Release自动加载, 订阅发布同步后端#16

Merged
lostiv merged 3 commits into
mainfrom
fix/front
May 12, 2026
Merged

refactor: Release迁移到后端代理, 添加Fork和Release自动加载, 订阅发布同步后端#16
lostiv merged 3 commits into
mainfrom
fix/front

Conversation

@lostiv
Copy link
Copy Markdown
Owner

@lostiv lostiv commented May 12, 2026

  • ReleaseTimeline: 移除GitHubApiService, 改用backend.getMultipleRepositoryReleases走后端代理
  • BackendAdapter: 新增fetchAllReleasesForRepo和getMultipleRepositoryReleases, getRepositoryReleases返回Release[]
  • ForkTimeline: 添加挂载时自动加载forks, 避免新开页面显示空状态
  • ReleaseTimeline: 添加挂载时自动加载releases
  • RepositoryCard: 订阅发布按钮同步调用backend.updateRepository持久化
  • useAppStore: setRepositories时从subscribed_to_releases自动重建releaseSubscriptions

- ReleaseTimeline: 移除GitHubApiService, 改用backend.getMultipleRepositoryReleases走后端代理
- BackendAdapter: 新增fetchAllReleasesForRepo和getMultipleRepositoryReleases, getRepositoryReleases返回Release[]
- ForkTimeline: 添加挂载时自动加载forks, 避免新开页面显示空状态
- ReleaseTimeline: 添加挂载时自动加载releases
- RepositoryCard: 订阅发布按钮同步调用backend.updateRepository持久化
- useAppStore: setRepositories时从subscribed_to_releases自动重建releaseSubscriptions
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6454f102-ee10-47d9-8459-171745a6f8af

📥 Commits

Reviewing files that changed from the base of the PR and between 94e6487 and b232906.

📒 Files selected for processing (1)
  • src/services/backendAdapter.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/services/backendAdapter.ts

📝 Walkthrough

Summary by CodeRabbit

发布说明

  • 新功能

    • 组件加载时自动获取用户的分支和已订阅的发布(首次可用时)
    • 并发批量获取多个仓库的发布列表,支持分页与增量抓取
  • 改进

    • 发布订阅交互先在本地更新并在后台同步,界面无阻塞
    • 同步仓库列表时自动同步发布订阅状态
  • 稳定性

    • 后端获取流程更鲁棒,按仓库收集错误且不影响总体结果

Walkthrough

将 Release 获取与订阅同步移至后端适配器,增加 Fork/Release 时间线挂载自动加载,类型化与并发/分页获取 Release,并在 RepositoryCard 中持久化订阅变更到后端。

变更清单

后端与状态管理集成

Layer / File(s) Summary
Release 数据服务强化
src/services/backendAdapter.ts
getRepositoryReleases 改为返回 Release[],新增 fetchAllReleasesForRepo(分页聚合)和 getMultipleRepositoryReleases(最多 3 并发、增量/过滤、失败收集)。
应用状态订阅同步
src/store/useAppStore.ts
setRepositories 同步 releaseSubscriptions,从 repositoriessubscribed_to_releases 标志构建订阅集合。
Release 时间线后端迁移
src/components/ReleaseTimeline.tsx
移除 GitHubApiServicegithubToken,添加挂载自动加载(initialLoadDone + cancelled),刷新逻辑改为调用 backend.getMultipleRepositoryReleases
Fork 时间线自动加载
src/components/ForkTimeline.tsx
挂载时在后端可用且 forks 为空时自动调用 backend.getUserForks(),使用 initialLoadDone 防止重复并用 cancelled 保护卸载后的更新。
Repository 卡片 subscription 同步
src/components/RepositoryCard.tsx
新增 handleToggleSubscription,先切换本地 store 状态,再在后端可用时非阻塞地调用 backend.updateRepository 持久化 subscribed_to_releases

Sequence Diagram(s)

sequenceDiagram
  participant ReleaseTimeline
  participant BackendAdapter
  participant Backend
  participant Store
  ReleaseTimeline->>Store: 读取 subscribed repositories
  ReleaseTimeline->>BackendAdapter: getMultipleRepositoryReleases(repos, options)
  BackendAdapter->>Backend: 并发请求各仓库 releases(分页/增量)
  Backend-->>BackendAdapter: 返回 Release[] 与 per-repo 错误
  BackendAdapter->>Store: 更新 releases 并返回 failedRepos
  ReleaseTimeline->>ReleaseTimeline: 更新 UI 状态(refresh flags)
Loading

代码审查工作量预估

🎯 4 (Complex) | ⏱️ ~45 minutes

可能相关的 PR

  • lostiv/GithubStarsManager#12: 同步将 Release/订阅逻辑迁移到后端适配器,修改 ReleaseTimeline 与 RepositoryCard 的后端调用路径。
  • lostiv/GithubStarsManager#15: 涉及 frontend/backend 集成重构,包含对 backend.getUserForks 与相关后端代理方法的调整。

建议标签

frontend

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 标题完全遵循 Conventional Commits 格式 (refactor: description),清晰准确地总结了本次 PR 的核心变更:后端代理迁移、自动加载功能和订阅同步。
Description check ✅ Passed 描述详细列举了 6 个方面的变更,与代码改动的文件和内容完全对应,为代码审查提供了充分的上下文信息。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/front
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/front

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/services/backendAdapter.ts (1)

240-242: 💤 Low value

直接修改传入对象存在副作用风险

releases.forEach 直接修改 release.repository.id,这是对 getRepositoryReleases 返回对象的原地修改。虽然当前场景下可行,但这种副作用模式可能导致难以追踪的 bug。

建议在映射时创建新对象:

建议修改
-          releases.forEach(release => {
-            release.repository.id = repo.id;
-          });
+          releases = releases.map(release => ({
+            ...release,
+            repository: { ...release.repository, id: repo.id }
+          }));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/backendAdapter.ts` around lines 240 - 242, The code mutates the
input releases in-place via releases.forEach(release => { release.repository.id
= repo.id; }), which creates side effects; instead, return or assign a new array
of release objects that copy each release and its repository and set
repository.id to repo.id (e.g., use releases.map to produce new objects) so
getRepositoryReleases (or the surrounding function that uses the releases
variable) does not alter the original input; update usages to consume the new
array rather than relying on in-place modification.
src/store/useAppStore.ts (1)

780-788: ⚡ Quick win

setRepositories 只添加订阅,未处理取消订阅同步

当前实现只在 subscribed_to_releases 为真时添加订阅,但如果后端数据中 subscribed_to_releasesfalse,本地已存在的订阅不会被移除。这可能导致本地订阅状态与后端不一致。

建议同时处理取消订阅的情况:

建议修改
 setRepositories: (repositories) => set((state) => {
   const nextReleaseSubscriptions = new Set(state.releaseSubscriptions);
   for (const repo of repositories) {
     if (repo.subscribed_to_releases) {
       nextReleaseSubscriptions.add(repo.id);
+    } else {
+      nextReleaseSubscriptions.delete(repo.id);
     }
   }
   return { repositories, searchResults: repositories, releaseSubscriptions: nextReleaseSubscriptions };
 }),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/store/useAppStore.ts` around lines 780 - 788, setRepositories currently
only adds repo ids to releaseSubscriptions when repo.subscribed_to_releases is
true and never removes ids when subscribed_to_releases is false, causing local
releaseSubscriptions to drift from backend. In the setRepositories updater
(function setRepositories in useAppStore.ts) build nextReleaseSubscriptions from
state.releaseSubscriptions, then for each repo in repositories add repo.id when
repo.subscribed_to_releases is true and remove repo.id when
repo.subscribed_to_releases is false; finally return the new repositories,
searchResults and releaseSubscriptions (nextReleaseSubscriptions) so local state
mirrors the backend.
src/components/RepositoryCard.tsx (1)

598-604: 💤 Low value

订阅状态同步采用乐观更新,后端失败静默忽略

当前实现先更新本地状态,后端调用失败时静默忽略(.catch(() => {}))。这可能导致:

  1. 用户认为订阅成功,但后端未持久化
  2. 刷新后订阅状态可能恢复

如果这是预期的 best-effort 行为,建议至少添加 console.warn 以便调试:

建议修改
 const handleToggleSubscription = () => {
   const newState = !isSubscribed;
   toggleReleaseSubscription(repository.id);
   if (backend.isAvailable) {
-    backend.updateRepository(repository.id, { subscribed_to_releases: newState }).catch(() => {});
+    backend.updateRepository(repository.id, { subscribed_to_releases: newState })
+      .catch((err) => console.warn('Failed to sync subscription state:', err));
   }
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/RepositoryCard.tsx` around lines 598 - 604, The
optimistic-update in handleToggleSubscription currently swallows backend errors;
modify the catch on backend.updateRepository(repository.id, {
subscribed_to_releases: newState }) to at minimum log a warning with the error
and repository.id (e.g., console.warn or processLogger.warn) so failures are
visible for debugging, and optionally revert the optimistic change by calling
toggleReleaseSubscription(repository.id) inside the catch if you want strict
consistency; keep references to handleToggleSubscription,
toggleReleaseSubscription, backend.updateRepository and repository.id when
making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ReleaseTimeline.tsx`:
- Around line 277-319: The auto-load useEffect around initialLoadDone currently
only depends on backend.isAvailable which can miss updates (and skips
includePreRelease); update the effect dependencies to include includePreRelease,
repositories (or a stable key derived from repositories), releaseSubscriptions
(or a stable subscription flag), releases.length (or initialLoadDone logic), and
stable callbacks used inside (addReleases, setReleaseIsRefreshing) so the effect
reruns when those change, or alternatively convert
includePreRelease/repositories/releaseSubscriptions to refs and read them inside
the effect to avoid stale closures; ensure the cleanup/cancel logic remains and
that setInitialLoadDone is set once load completes.

In `@src/services/backendAdapter.ts`:
- Around line 173-187: The fetchAllReleasesForRepo function lacks error handling
and a guard against infinite paging; modify fetchAllReleasesForRepo to accept or
define a maxPages constant (e.g., 100) and stop paging when page > maxPages,
wrap the await this.getRepositoryReleases(...) call in try/catch to
log/propagate errors, and add a request timeout or abort logic around
getRepositoryReleases (or enforce a per-request timeout) so a single slow
request can't hang the loop; reference functions fetchAllReleasesForRepo and
getRepositoryReleases when making these changes.

---

Nitpick comments:
In `@src/components/RepositoryCard.tsx`:
- Around line 598-604: The optimistic-update in handleToggleSubscription
currently swallows backend errors; modify the catch on
backend.updateRepository(repository.id, { subscribed_to_releases: newState }) to
at minimum log a warning with the error and repository.id (e.g., console.warn or
processLogger.warn) so failures are visible for debugging, and optionally revert
the optimistic change by calling toggleReleaseSubscription(repository.id) inside
the catch if you want strict consistency; keep references to
handleToggleSubscription, toggleReleaseSubscription, backend.updateRepository
and repository.id when making the change.

In `@src/services/backendAdapter.ts`:
- Around line 240-242: The code mutates the input releases in-place via
releases.forEach(release => { release.repository.id = repo.id; }), which creates
side effects; instead, return or assign a new array of release objects that copy
each release and its repository and set repository.id to repo.id (e.g., use
releases.map to produce new objects) so getRepositoryReleases (or the
surrounding function that uses the releases variable) does not alter the
original input; update usages to consume the new array rather than relying on
in-place modification.

In `@src/store/useAppStore.ts`:
- Around line 780-788: setRepositories currently only adds repo ids to
releaseSubscriptions when repo.subscribed_to_releases is true and never removes
ids when subscribed_to_releases is false, causing local releaseSubscriptions to
drift from backend. In the setRepositories updater (function setRepositories in
useAppStore.ts) build nextReleaseSubscriptions from state.releaseSubscriptions,
then for each repo in repositories add repo.id when repo.subscribed_to_releases
is true and remove repo.id when repo.subscribed_to_releases is false; finally
return the new repositories, searchResults and releaseSubscriptions
(nextReleaseSubscriptions) so local state mirrors the backend.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d3e2e633-d338-47e1-af4a-1229904385c4

📥 Commits

Reviewing files that changed from the base of the PR and between 1044444 and 871dabf.

📒 Files selected for processing (5)
  • src/components/ForkTimeline.tsx
  • src/components/ReleaseTimeline.tsx
  • src/components/RepositoryCard.tsx
  • src/services/backendAdapter.ts
  • src/store/useAppStore.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
src/components/**

⚙️ CodeRabbit configuration file

src/components/**: React 组件目录(TypeScript + Tailwind CSS)。审查时请关注: 1. 是否同时兼容暗色(dark: 前缀)和亮色主题 2. 响应式布局是否完整(Tailwind 断点系统:sm/md/lg/xl) 3. Props 类型定义是否完整(TypeScript interface) 4. 组件是否保持单一职责 5. 无障碍访问(aria-label、role、键盘导航) 6. React.memo / useMemo / useCallback 的使用是否合理

Files:

  • src/components/RepositoryCard.tsx
  • src/components/ForkTimeline.tsx
  • src/components/ReleaseTimeline.tsx
src/store/**

⚙️ CodeRabbit configuration file

src/store/**: Zustand 状态管理。审查时请关注: 1. 持久化存储(IndexedDB)的数据结构和版本迁移 2. Selector 的细粒度订阅(避免不必要的重渲染) 3. 敏感数据是否被持久化到客户端 4. 状态更新的原子性和一致性

Files:

  • src/store/useAppStore.ts
src/services/**

⚙️ CodeRabbit configuration file

src/services/**: API 服务层。审查时请关注: 1. fetch 请求的超时处理(AbortController) 2. 错误处理和用户友好的错误信息翻译 3. API 密钥/Token 的传输安全性 4. 请求重试和降级策略 5. WebDAV/后端代理的 CORS 处理

Files:

  • src/services/backendAdapter.ts
🔇 Additional comments (2)
src/services/backendAdapter.ts (1)

200-203: 并发索引递增在 async 上下文中的安全性说明

index++ 在多个 async worker 中使用。由于 JavaScript 事件循环的单线程特性,这实际上是安全的——index++ 是同步操作,在 await 之前完成。当前实现正确。

src/components/ReleaseTimeline.tsx (1)

343-409: handleRefresh 实现完善,错误处理得当

刷新逻辑:

  • 正确检查 backend 可用性
  • 正确处理空订阅情况
  • 区分成功/失败仓库并给出相应提示
  • 更新仓库的 has_fetched_releaseslast_release_fetch_time 元数据
  • 过滤重复 releases 后添加

实现逻辑清晰,错误处理完善。

Comment on lines +277 to +319
// Auto-load releases on mount if empty
const [initialLoadDone, setInitialLoadDone] = useState(false);

useEffect(() => {
if (initialLoadDone) return;
if (!backend.isAvailable) return;
if (releases.length > 0) {
setInitialLoadDone(true);
return;
}

const subscribedRepos = repositories.filter(repo => releaseSubscriptions.has(repo.id));
if (subscribedRepos.length === 0) {
setInitialLoadDone(true);
return;
}

let cancelled = false;
const loadReleases = async () => {
setReleaseIsRefreshing(true);
try {
const { releases: newReleases } = await backend.getMultipleRepositoryReleases(
subscribedRepos,
{ includePreRelease }
);
if (cancelled) return;
if (newReleases.length > 0) {
addReleases(newReleases);
}
setInitialLoadDone(true);
} catch {
// Silent fail on auto-load
} finally {
if (!cancelled) {
setReleaseIsRefreshing(false);
}
}
};
loadReleases();

return () => { cancelled = true; };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [backend.isAvailable]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

自动加载逻辑与 ForkTimeline 存在相同的依赖项问题

与 ForkTimeline 类似,backend.isAvailable 作为 useEffect 依赖项可能无法正确触发重新执行。

此外,注意 includePreRelease 未包含在依赖数组中(被 eslint-disable 跳过),如果用户在加载完成前切换此选项,可能导致数据不一致。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ReleaseTimeline.tsx` around lines 277 - 319, The auto-load
useEffect around initialLoadDone currently only depends on backend.isAvailable
which can miss updates (and skips includePreRelease); update the effect
dependencies to include includePreRelease, repositories (or a stable key derived
from repositories), releaseSubscriptions (or a stable subscription flag),
releases.length (or initialLoadDone logic), and stable callbacks used inside
(addReleases, setReleaseIsRefreshing) so the effect reruns when those change, or
alternatively convert includePreRelease/repositories/releaseSubscriptions to
refs and read them inside the effect to avoid stale closures; ensure the
cleanup/cancel logic remains and that setInitialLoadDone is set once load
completes.

Comment thread src/services/backendAdapter.ts
@lostiv
Copy link
Copy Markdown
Owner Author

lostiv commented May 12, 2026

关于第5条 (auto-load useEffect 依赖不完整): 不同意此建议。

当前 useEffect(() => { ... }, [backend.isAvailable]) 是有意设计的,只需要在组件挂载且后端可用时执行一次自动加载。eslint-disable-next-line react-hooks/exhaustive-deps 注释已经说明了意图。

如果按建议加上 includePreReleaserepositoriesreleaseSubscriptions 等依赖项,会导致这些值每次变化时都重新触发自动加载,这不是想要的行为。自动加载的语义是"首次挂载时加载一次",而不是"依赖变化时重新加载"。

initialLoadDone 标志位 + cancelled cleanup 已经保证了安全性和幂等性。

@lostiv
Copy link
Copy Markdown
Owner Author

lostiv commented May 12, 2026

@coderabbitai 请查看上一条回复,回复你对 ReleaseTimeline.tsx useEffect 依赖项的建议。

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 2026

Tip

For best results, initiate chat on the files or code changes.

@lostiv 感谢说明,您的解释完全合理。

"首次挂载时加载一次"的语义确实与"依赖变化时重新加载"是两种不同的 effect 模式:

  • 当前的 initialLoadDone 标志位充当了一次性执行的守卫,确保幂等性。
  • cancelled 标志防止了组件卸载后的状态更新(内存泄漏)。
  • eslint-disable-next-line react-hooks/exhaustive-deps 注释已明确记录了绕过 exhaustive-deps 规则的意图。

在这种"挂载触发、仅执行一次"的场景下,人为限制依赖项是合理的做法,无需补全所有引用变量作为依赖。我撤回该建议。

(・_・)っ


✏️ Learnings added
Learnt from: lostiv
URL: https://github.com/lostiv/GithubStarsManager/pull/16

Timestamp: 2026-05-12T02:12:04.298Z
Learning: In ReleaseTimeline.tsx (React 18 + TypeScript), the auto-load useEffect is intentionally written with only `[backend.isAvailable]` as dependency, not the full exhaustive deps list. The design intent is "load once on mount when backend becomes available", not "reload whenever deps change". An `initialLoadDone` ref flag guards against re-runs, and a `cancelled` flag prevents post-unmount state updates. The `eslint-disable-next-line react-hooks/exhaustive-deps` comment documents this intentional decision. Do not suggest adding `includePreRelease`, `repositories`, or `releaseSubscriptions` to the dependency array.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

- backendAdapter: releases.forEach 改 map 避免原地修改副作用
- backendAdapter: fetchAllReleasesForRepo 加 maxPages=50 上限和 try/catch
- useAppStore: setRepositories 同时处理取消订阅 (subscribed_to_releases=false)
- RepositoryCard: 订阅同步失败改为 console.warn 记录
@coderabbitai coderabbitai Bot added backend and removed frontend labels May 12, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/services/backendAdapter.ts`:
- Around line 226-243: The incremental fetch loop in backendAdapter (the
while(true) that calls getRepositoryReleases) lacks the maxPages cap and
inter-request delay used in fetchAllReleasesForRepo; update that loop to enforce
a maxPages (e.g., 50) and a small sleep (e.g., 100ms) between iterations,
incrementing page and breaking when page >= maxPages or when batch length <
pageSize or a release <= sinceTime is found; ensure the logic still respects
sinceTime (including null first-run behavior) and reuse the same page, maxPages
and delay variable names as in fetchAllReleasesForRepo for clarity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 507c9cee-86f7-42c5-9907-1870ee36f074

📥 Commits

Reviewing files that changed from the base of the PR and between 871dabf and 94e6487.

📒 Files selected for processing (3)
  • src/components/RepositoryCard.tsx
  • src/services/backendAdapter.ts
  • src/store/useAppStore.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/store/useAppStore.ts
  • src/components/RepositoryCard.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
src/services/**

⚙️ CodeRabbit configuration file

src/services/**: API 服务层。审查时请关注: 1. fetch 请求的超时处理(AbortController) 2. 错误处理和用户友好的错误信息翻译 3. API 密钥/Token 的传输安全性 4. 请求重试和降级策略 5. WebDAV/后端代理的 CORS 处理

Files:

  • src/services/backendAdapter.ts
🔇 Additional comments (3)
src/services/backendAdapter.ts (3)

144-171: LGTM - getRepositoryReleases 类型映射实现良好

使用 fetchWithTimeout 处理超时,try/catch 错误处理返回空数组作为降级策略,符合服务层规范。


173-193: LGTM - 分页保护和错误处理已完善

maxPages = 50 限制、try/catch 错误处理、以及 100ms 延迟都已实现,符合之前的改进建议。


195-268: LGTM - 并发控制和错误收集模式良好

  • 3 个并发 worker 限制合理
  • 每个仓库独立错误收集 (failedRepos),不会因单个失败导致整体失败
  • includePreRelease 过滤逻辑清晰

Comment thread src/services/backendAdapter.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant