Skip to content

Chat shell endpoints module and hub error migration - #287

Merged
steve02081504 merged 15 commits into
masterfrom
split/chat
Aug 7, 2026
Merged

Chat shell endpoints module and hub error migration#287
steve02081504 merged 15 commits into
masterfrom
split/chat

Conversation

@steve02081504

@steve02081504 steve02081504 commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • Move chat frontend HTTP clients from api to endpoints (incl. emoji pack splits)
  • Migrate hub/shared/profile/src to centralized handleError
  • Related chat backend/test tweaks from lava

Stacking

Test plan

  • Open chat hub; send message / switch channels
  • fount test --no-parallel chat-related selectors
  • Confirm no imports of chat public/src/api/

摘要

  • 将 Chat 前端 HTTP 请求迁移到 src/endpoints,统一封装群组、频道、实体、偏好、表情包、文件和联邦接口。
  • 将 UI 与后台模块统一改用 handleError,删除旧 api 客户端、重复请求处理和静默异常。
  • 补充书签后端接口与测试,并管理群文件 Blob URL 生命周期。
  • 优化抽屉、关闭按钮、媒体上传控件的无障碍文本和本地化结构。

架构与审美风险

  • endpoint 同时承担请求封装、响应规范化和业务转换,职责过重。
  • 大规模迁移扩大异步错误、动态导入和循环依赖的回归面。
  • handleError 横跨 UI 与后台模块,统一性提升,但耦合范围过大。
  • 需要确认不存在 chat/public/src/api/ 残留引用,并避免 endpoint 默认值掩盖后端契约错误。

@cursor

cursor Bot commented Aug 7, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c032cc23-289a-4c49-ae69-8c36ff333a01

📥 Commits

Reviewing files that changed from the base of the PR and between bbf4051 and 4fca0b8.

📒 Files selected for processing (22)
  • src/decl/locale_data.ts
  • src/public/locales/ar-SA.json
  • src/public/locales/de-DE.json
  • src/public/locales/emoji.json
  • src/public/locales/en-UK.json
  • src/public/locales/es-ES.json
  • src/public/locales/fr-FR.json
  • src/public/locales/hi-IN.json
  • src/public/locales/is-IS.json
  • src/public/locales/it-IT.json
  • src/public/locales/ja-JP.json
  • src/public/locales/ko-KR.json
  • src/public/locales/lzh.json
  • src/public/locales/nl-NL.json
  • src/public/locales/pt-PT.json
  • src/public/locales/ru-RU.json
  • src/public/locales/uk-UA.json
  • src/public/locales/vi-VN.json
  • src/public/locales/zh-CN.json
  • src/public/locales/zh-TW.json
  • src/public/parts/shells/chat/public/hub/chatConfig.mjs
  • src/public/parts/shells/chat/public/hub/index.html

📝 Walkthrough

Walkthrough

Chat Shell 将原始 HTTP 请求迁移到命名 endpoint,并统一使用 handleError。新增群组、实体、文件、偏好、治理、发现、表情包和书签接口,同时调整媒体生命周期、后台异步错误、治理流程及无障碍文案。

Changes

Chat endpoint migration

Layer / File(s) Summary
Endpoint 基础与请求契约
src/public/parts/shells/chat/public/src/endpoints/*
新增 Chat、群组、实体、文件、表情、偏好、联邦、治理、发现和书签 endpoint。请求、响应及字段默认值集中处理。
前端调用迁移与错误处理
src/public/parts/shells/chat/public/hub/*, src/public/parts/shells/chat/public/profile/*, src/public/parts/shells/chat/public/shared/*, src/public/parts/shells/chat/public/providers/*
UI、shared、providers 和 profile 模块移除内联 fetch,改用命名 endpoint。异步错误统一交给 handleError
媒体生命周期与消息状态
src/public/parts/shells/chat/public/hub/messages/render/file.mjs, src/public/parts/shells/chat/public/src/groupFileBlob.mjs, src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs
EVFS 文件读取改用 endpoint。系统按频道跟踪并释放 Blob URL。消息列表销毁和媒体节点移除时执行清理。
后台治理与书签状态
src/public/parts/shells/chat/src/chat/*, src/public/parts/shells/chat/src/group/routes/governance.mjs, src/public/parts/shells/chat/src/api/client/privateState.mjs, src/public/parts/shells/chat/src/endpoints/preferences.mjs
后台异步任务统一处理错误。封禁流程增加声誉扣减告警。书签支持原子添加、去重和删除,并增加对应路由及测试。
无障碍国际化结构
src/decl/locale_data.ts, src/public/locales/*.json, src/public/pages/i18n-notes.md, src/public/parts/shells/{home,social,cabinet}/public/*
关闭按钮和媒体控件改用隐藏文本承载翻译键。抽屉结构使用语义化 landmark。相关本地化类型和资源同步更新。

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
审美与简洁 ⚠️ Warning 新增 endpoints 仍有冗余防御与旧数据兼容:emojiPacks.mjs:15、groupCore.mjs:155/158/276;entities.mjs:135/137、143,且 q/qs/path 是一次性短绑定。 按后端 DTO 直接使用 packs、entries、types;删除 Array.isArray、旧 banner/status fallback;将 q、qs、path 内联或改为语义名称。
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了聊天 Shell 的 endpoint 迁移和 Hub 错误处理迁移,符合简洁说明变更目的的要求。
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch split/chat

Warning

Review ran into problems

🔥 Problems

Repository analysis: Couldn't refresh steve02081504/fount clone - clone failed: Clone operation failed: Stream initialization permanently failed: 14 UNAVAILABLE: read ECONNRESET


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@codacy-production

codacy-production Bot commented Aug 7, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 2 medium

Alerts:
⚠ 2 issues (≤ 0 issues of at least minor severity)

Results:
2 new issues

Category Results
Complexity 2 medium

View in Codacy

🟢 Metrics 161 complexity · 0 duplication

Metric Results
Complexity 161
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Base automatically changed from split/deps to master August 7, 2026 09:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 37

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
src/public/parts/shells/chat/public/hub/memberReadMarkers.mjs (1)

33-38: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

不要静默吞掉成员读取标记请求失败。

getMemberReadMarkers(...) 的拒绝在空 catch 中直接变成 {}。请求失败不会经过统一错误处理。请调用 handleError('chat.hub.operationFailed'),再返回空标记。

As per path instructions,异步失败必须通过 handleError(...) 处理,不能由空 catch 静默返回。

建议补充统一错误处理
 import { getMemberReadMarkers } from '../src/endpoints/groupChannel.mjs'
+import { handleError } from '/scripts/features/errorHandlers.mjs'

 ...

-	catch { return {} }
+	catch (error) {
+		handleError('chat.hub.operationFailed')(error)
+		return {}
+	}
🤖 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/public/parts/shells/chat/public/hub/memberReadMarkers.mjs` around lines
33 - 38, Update the catch block in the member read-marker request flow around
getMemberReadMarkers to call handleError('chat.hub.operationFailed') before
returning the empty marker object. Preserve the existing fallback return value
while ensuring the rejection is routed through unified error handling.

Source: Path instructions

src/public/parts/shells/chat/public/src/endpoints/channelArchive.mjs (1)

91-94: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

不要吞掉事件响应契约错误。

Array.isArray(data.events) ? data.events : [] 会把损坏响应伪装成“没有事件”。调用方会错误地显示空历史。直接返回端点契约字段,让错误暴露。

建议修改
 	return {
-		events: Array.isArray(data.events) ? data.events : [],
-		truncated: !!data.truncated,
+		events: data.events,
+		truncated: data.truncated,
 	}

As per path instructions, “前后端互信”且“垃圾数据直接炸”。

🤖 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/public/parts/shells/chat/public/src/endpoints/channelArchive.mjs` around
lines 91 - 94, 修改 channelArchive 端点中处理 data.events
的逻辑,移除将非数组值替换为空数组的兜底行为,直接返回契约字段 data.events;响应数据损坏时应让契约错误暴露,而不是伪装成空历史。

Source: Path instructions

src/public/parts/shells/chat/public/src/groupSettings/membersTab.mjs (1)

18-26: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

kickMember 内处理 endpoint rejection。

kickMemberRequest 失败时会 reject。DOM 事件分派不会等待 Line 124 的异步监听器。将请求、成功提示和 reload 包进 try,并在 catch 中调用 handleError。失败时不要显示成功提示或刷新状态。

As per path instructions, “Route failures through handleError(messageKey)(error), including floating/background promises via .catch(handleError)”.

🤖 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/public/parts/shells/chat/public/src/groupSettings/membersTab.mjs` around
lines 18 - 26, Update kickMember so kickMemberRequest, the success toast, and
context.reload run inside a try block; catch request or reload rejections and
pass them to handleError with the appropriate message key. Ensure failures do
not show the success toast or reload state, and attach catch handling for any
floating async event-dispatch promise as required.

Source: Path instructions

src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs (1)

29-37: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

统一 chat Hub 的异步故障处理。

这些路径绕过了 handleError('chat.hub.…')。因此错误不会进入统一的 toast、console 和 Sentry 流程。

  • src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs#L29-L37:改为 async 监听器,等待 putTranslationPrefs,并在 catch 中调用 handleError
  • src/public/parts/shells/chat/public/hub/memberContextMenu.mjs#L138-L147:等待 renderMemberList,并将踢出、状态刷新和重绘失败交给 handleError
  • src/public/parts/shells/chat/public/hub/messages/render/translation.mjs#L42-L45:不要吞掉翻译和偏好读取失败;使用对应的 handleError 处理器。
🤖 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/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs` around
lines 29 - 37, Unify asynchronous error handling across the three affected
sites: in
src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs:29-37, make
the save listener async, await putTranslationPrefs, and route failures through
handleError; in
src/public/parts/shells/chat/public/hub/memberContextMenu.mjs:138-147, await
renderMemberList and pass kick, status-refresh, and redraw failures to
handleError; in
src/public/parts/shells/chat/public/hub/messages/render/translation.mjs:42-45,
stop swallowing translation and preference-read failures and use the
corresponding handleError handlers.

Sources: Coding guidelines, Path instructions

🤖 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/public/parts/shells/chat/public/hub/banners.mjs`:
- Line 170: Replace the Promise chain at
src/public/parts/shells/chat/public/hub/banners.mjs:170-170 with an async helper
using try/catch, await refreshDagForkBanner(), then await
refreshLocalViewBanner(), and route failures through
handleError('chat.hub.operationFailed'). Also replace the .then(...).catch(...)
chain at
src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs:353-355 with
try/catch using await import(...) and await fetchMemberReadMarkers(...),
handling errors through the existing handleError(...) mechanism.

In `@src/public/parts/shells/chat/public/hub/call.mjs`:
- Around line 521-524: Update the catch block around getCallStatus in the
call-status update flow to stop swallowing request failures. Let the rejection
propagate so the caller’s error handler runs, or route it through handleError
using the established chat.hub error context while preserving toast, console,
and Sentry handling.

In `@src/public/parts/shells/chat/public/hub/files.mjs`:
- Line 125: 将包含 bindCabinetFlow 和 refreshFilesDrawer 的点击处理器改为 async 函数,移除
then/catch 链,并在 try 中依次 await bindCabinetFlow(drawer.groupId, state) 与
refreshFilesDrawer(drawer);在 catch 中将捕获的 error 传给
handleError('chat.hub.files.loadFailed')。

In `@src/public/parts/shells/chat/public/hub/friendsList.mjs`:
- Around line 488-491: Route all listed endpoint failures through the unified
handleError(messageKey)(error) flow: update friendsList.mjs lines 488-491 to
replace the local toast catch, preserve silent behavior and only handle
non-silent failures in hubStatus.mjs lines 74-79, and update the catches in
profile/index.mjs lines 96, 136, 184, and 220-228 to use the specified named
error keys. In ownerSettingsPanel.mjs lines 38-44 and 84-95, route viewer,
profile, owner-save, and owner-clear failures through handleError with
appropriate message keys, removing direct toast, console, or silent handling
where applicable.

In `@src/public/parts/shells/chat/public/hub/hubStatus.mjs`:
- Line 63: Update sendHeartbeat in
src/public/parts/shells/chat/public/hub/hubStatus.mjs at line 63 to route
postEntityHeartbeat(entityHash) rejections through a .catch closure calling the
appropriate handleError('chat.hub.…') key. Update openHubProfileEdit in
src/public/parts/shells/chat/public/hub/profileEdit.mjs at line 816 to catch
getEntityProfile rejection, call handleError('chat.profile.errors.loadFailed'),
and stop opening the dialog.

In `@src/public/parts/shells/chat/public/hub/inboxClient.mjs`:
- Around line 19-21: 删除 inboxClient.mjs 中仅转发 fetchInboxPageApi 的 fetchInboxPage
函数及其导出;更新 inboxView.mjs,改为直接从 ../src/endpoints/inbox.mjs 导入 fetchInboxPage。保留
markInboxSeen 及其现有 badge 状态更新逻辑,不添加弃用标记或重新导出。

In `@src/public/parts/shells/chat/public/hub/initCore.mjs`:
- Around line 19-20: Route failures from getViewer() and whoami() in
initCore.mjs through handleError(messageKey)(error) before returning null,
preserving the existing partial initialization flow. Apply the same handling in
deepLinkConsume.mjs at the nodeHash lookup, calling handleError before returning
{} so the PoW fallback remains intact; update both listed sites accordingly.
- Around line 18-23: 在 initCore 初始化流程中,将 Promise.all 返回的 data 和 who 重命名为 viewer
与 identity,并同步更新后续判断和赋值逻辑;使用 identity.username 直接赋值给 store.viewer.username,保留
viewer 为空时提前返回的行为。

In `@src/public/parts/shells/chat/public/hub/mentionAutocomplete.mjs`:
- Around line 108-114: Remove the catch block around suggestMentions in the
onInput flow so its rejection propagates to the existing handleError(messageKey)
handler, which must continue hiding the panel. Preserve the successful
render(data.suggestions || []) behavior and route failures through
handleError(messageKey)(error).

In `@src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs`:
- Line 351: Update the call to refreshChannelPinsBar() in the message refresh
flow to attach the required .catch(handleError(...)) failure handling. Preserve
the existing asynchronous invocation while routing template-rendering failures
through the established unified error handler instead of leaving the Promise
rejection unhandled.

In `@src/public/parts/shells/chat/public/hub/serverBar.mjs`:
- Around line 219-222: Update the getGroupFolders() rejection handler in the
Promise.all flow to pass the caught error through
handleError('chat.hub.operationFailed') before returning null. Preserve the
existing null fallback while ensuring the failure reaches the shared error
logging and Sentry path.
- Around line 234-235: 在处理 foldersPayload 的逻辑中移除
Array.isArray(foldersPayload.folders) 的类型回退,直接使用 foldersPayload.folders 作为
rawFolders。保留 getGroupFolders() 本机 endpoint 的既有契约,不要将类型错误转换为空文件夹。

In `@src/public/parts/shells/chat/public/hub/sidebar/federationRoom.mjs`:
- Around line 20-23: Route all endpoint failures through the curried
handleError(messageKey)(error) API: in
src/public/parts/shells/chat/public/hub/sidebar/federationRoom.mjs:20-23, change
the rebind failure call accordingly; in
src/public/parts/shells/chat/public/hub/core/bindings.mjs:223-234, make the
click handler async, await the operation, and replace catch(console.error) with
the appropriate handleError call; in
src/public/parts/shells/chat/public/src/groupSettings/channelPermsTab.mjs:119-127,
include getChannelPermissions and permission reads/writes within failure
handling; and in
src/public/parts/shells/chat/public/src/groupSettings/permissionsTab.mjs:84-84,
catch deleteRoleRequest rejection and invoke its corresponding handleError.

In `@src/public/parts/shells/chat/public/hub/sidebar/groupMembership.mjs`:
- Line 39: Remove the single-use catchupError binding in the chat hub sync error
handling and inline handleError('chat.hub.sync.failed')(error).message directly
into the params.error assignment.

In `@src/public/parts/shells/chat/public/hub/sidebar/selectChannel.mjs`:
- Line 85: Update loadDraft in composerDraft.mjs to reset the editor fields,
content warnings, and sensitive-media state before checking for or applying the
saved draft; preserve the existing draft-loading behavior when a draft exists,
while ensuring an empty result leaves the editor fully cleared. Keep the
selectChannel call unchanged.

In `@src/public/parts/shells/chat/public/hub/unread.mjs`:
- Around line 8-11: 统一 unread.mjs 中后台刷新异步路径:将 refreshServerBar 及相关调用
renderHubChannelSidebar、applyMemberReadMarkerWire 的 helper 改为 async 并使用 await,移除
import().then(...)。当前 async 调用方直接 await;必须后台执行的调用则附加
.catch(handleError('chat.hub.operationFailed')),确保所有拒绝都通过 handleError 处理。

In `@src/public/parts/shells/chat/public/shared/evfsMedia.mjs`:
- Around line 2-3: Update the import of uploadEvfsAttachment in social media
module to reference the EVFS HTTP endpoint module at
/scripts/endpoints/p2p/evfsMedia.mjs instead of the chat shared evfsMedia.mjs
URL-only module, preserving the existing upload entry point and shell route
mapping.

In `@src/public/parts/shells/chat/public/src/endpoints/emoji.mjs`:
- Around line 10-16: Remove the catch-and-empty-payload fallbacks from
getEmojiUsage, the pack-list endpoint at
src/public/parts/shells/chat/public/src/endpoints/emoji.mjs#L23-L31, and the
offers endpoint at
src/public/parts/shells/chat/public/src/endpoints/emoji.mjs#L46-L53, allowing
chatFetch failures to reject. Update each corresponding consumer to route the
rejection through handleError(messageKey)(error): usage consumers at `#L10-L16`,
pack-list consumers at `#L23-L31`, and discovery-page consumers at `#L46-L53`.

In `@src/public/parts/shells/chat/public/src/endpoints/entities.mjs`:
- Around line 26-28: 在 entities.mjs 的 getEntityProfile 中将缩写变量 qs 重命名为
queryString,并同步更新其引用;在同文件第 90-93 行将 q 重命名为 query、opts 重命名为
options,并同步更新所有引用。受影响位置为
src/public/parts/shells/chat/public/src/endpoints/entities.mjs:26-28 和
src/public/parts/shells/chat/public/src/endpoints/entities.mjs:90-93。
- Around line 21-35: 为导出的 getEntityProfile 和 updateEntityProfile JSDoc
分别补充有意义的一行摘要,准确描述获取实体资料和更新实体资料的行为;保留现有参数与返回值标签,避免留下只有标签的无效 JSDoc。

In `@src/public/parts/shells/chat/public/src/endpoints/federationSettings.mjs`:
- Line 5: 删除 federationSettings.mjs 的纯重导出层,将 getFederationSettings 和
putFederationSettings 的完整 endpoint 实现移入该模块,并从 p2p.mjs
移除这两个实现及其导出;确保新实现保留原有行为并添加有意义的一行 JSDoc,避免任何重导出或 `@deprecated` 兼容层。

In `@src/public/parts/shells/chat/public/src/endpoints/groupBan.mjs`:
- Around line 24-28: 更新 banMemberWithScope() 及其服务端接口,将
member_ban、reputation_slash
和相关副作用合并为同一个原子且幂等的服务端操作,使用稳定的请求/事件标识避免重试重复追加签名事件或重复扣减。接口需返回部分成功状态,以便 UI
识别封禁已生效但声誉扣减需要恢复或重试。
- Around line 8-23: 删除 banMemberWithScope 中对 targetPubKeyHash 的
String/trim/lowercase 归一化、isHex64 校验及其导入;直接传递本地 Hub 提供的 targetPubKeyHash,并直接使用
options.banScope。保留后端入站路由对外部请求的有效性校验。

In `@src/public/parts/shells/chat/public/src/endpoints/groupBookmarks.mjs`:
- Around line 24-25: Replace the read-modify-write flow in addChatBookmark and
removeChatBookmark with server-side atomic add/remove bookmark operations, or
add an equivalent version/conditional write to saveChatBookmarks; do not
continue issuing unconditional full-list PUT requests based on a previously
fetched snapshot. Update saveChatBookmarks and its callers consistently while
preserving the intended add and remove behavior under concurrent requests.
- Around line 1-6: 修正 groupBookmarks.mjs 顶部 JSDoc 中过时的书签数据结构说明,使其与 bookmark.mjs
传入的 eventId、title、href 字段及 removeChatBookmark 按 href 删除的实际契约一致;如无法准确维护该
schema,则删除重复的数据结构声明。

In `@src/public/parts/shells/chat/public/src/endpoints/groupClient.mjs`:
- Around line 26-38: Update chatFetch so the JSON-derived body and headers are
not overwritten by the later ...init spread; ensure calls using the json option
send JSON.stringify(json) as the request body while preserving caller options
for non-JSON requests.

In `@src/public/parts/shells/chat/public/src/endpoints/groupCore.mjs`:
- Around line 12-15: 在 getGroupChatConfig 的 JSDoc
标签之前添加一行有意义的摘要,明确说明该函数用于获取群聊天配置,并保留现有参数与返回值注释不变。
- Around line 193-215: 恢复好友聊天取消传递:在
src/public/parts/shells/chat/public/src/endpoints/groupCore.mjs 的
createFriendGroup、listGroupChars 和 addGroupChar(193-215)中接收 AbortSignal 并传给
groupFetch;在 src/public/parts/shells/chat/public/hub/friendChat.mjs 的
ensureCharOnGroup 和 resolveFriendGroupId(93-128)中接收 signal,并在每个写操作前后检查取消状态;在同文件
256 行将当前 signal 传入 resolveFriendGroupId。
- Around line 91-105: 移除端点层对输入参数的防御性清洗:在 leaveGroups 中直接使用声明的
groupIds,不再强制转换、裁剪、过滤或去重;在 getMembersPage 中直接使用 pageIndex,不再将负值改为第 0 页。同步将
leaveGroups 的循环变量 i 重命名为 offset,并将 getMembersPage 中的 pageIdx 重命名为
pageIndex,保持其余请求与返回逻辑不变。

In `@src/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs`:
- Around line 38-43: Remove the dual-form input handling from blockUser and make
it accept only an object containing scope, value, and groupId. Delete the
entry?.scope conditional, string-input fallback, and optional groupId
resolution; pass the provided object directly to addDenylistEntry.

In `@src/public/parts/shells/chat/public/src/endpoints/prefs.mjs`:
- Around line 24-26: 将 prefs.mjs 中相关 JSDoc 的英文摘要改为中文领域描述,涵盖 cared
entityHashes、translation prefs、trusted authors 和 personal lists
对应的四处注释;保留现有返回类型标注,仅替换描述文本,确保摘要不再仅含拉丁字符。

In `@src/public/parts/shells/chat/public/src/groupFileBlob.mjs`:
- Around line 18-24: Remove the try/catch surrounding fetchEvfsFile and Blob
creation in fetchGroupFileAsBlobUrl so failures reject naturally. Preserve the
successful object-URL return, allowing the groupFileUpload.mjs caller’s
handleError path to report the error and return null.

In `@src/public/parts/shells/chat/public/src/groupSettings/permissionsTab.mjs`:
- Around line 94-97: Update showCreateRoleModal to be async and replace the
createRole promise chain with try/catch using await. Preserve the success toast
and context.reload flow on success, and show the existing failure toast with
error.message when creation fails.

In `@src/public/parts/shells/chat/public/src/groupViewerPermissions.mjs`:
- Line 30: Route all listed endpoint and operation failures through
handleError(messageKey)(error) instead of swallowing errors or using local
handling. In
src/public/parts/shells/chat/public/src/groupViewerPermissions.mjs:30, report
the permission-query error before returning {}; in
src/public/parts/shells/chat/public/emoji-packs/index.mjs:93-109, provide
operation error keys and handle rejected button actions; in
src/public/parts/shells/chat/public/hub/chatConfig.mjs:91, 111, 124, 138, 156,
and 183, replace each persona, world, plugin, frequency, and character local
failure handler; in src/public/parts/shells/chat/public/hub/misc.mjs:44-56,
handle drag-and-drop failures; and in
src/public/parts/shells/chat/public/src/groupSettings/emojisTab.mjs:47-56, 101,
and 123-164, report list/detail failures while preserving empty-data fallbacks
and handle save, create, upload, and delete failures.

In `@src/public/parts/shells/chat/public/src/lib/personalFilterClient.mjs`:
- Around line 18-23: Update fetchPersonalFilterSets() so request errors
propagate instead of returning EMPTY, preventing failed loads from being cached
as an empty personal-filter set. Handle the propagated error at the UI boundary
in loadHubPersonalFilter() using handleError('chat.hub.operationFailed'), while
preserving normal successful response normalization.

In `@src/public/parts/shells/chat/public/src/ui/groupFileUpload.mjs`:
- Line 261: Remove the empty catch attached to resumeGroupFileDownload in the
hasParts branch so its rejection propagates to the surrounding download error
handling. Ensure the failure reaches handleError and terminates the EVFS read
instead of continuing silently.

In `@src/public/parts/shells/chat/test/pure/viewer_log_dispatch.test.mjs`:
- Line 22: 将 getForViewer 回调的第一个参数从缩写 req 重命名为完整的 request,保留 viewer
作为第二个参数,并同步更新该回调内部对该参数的所有引用。

---

Outside diff comments:
In `@src/public/parts/shells/chat/public/hub/memberReadMarkers.mjs`:
- Around line 33-38: Update the catch block in the member read-marker request
flow around getMemberReadMarkers to call handleError('chat.hub.operationFailed')
before returning the empty marker object. Preserve the existing fallback return
value while ensuring the rejection is routed through unified error handling.

In `@src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs`:
- Around line 29-37: Unify asynchronous error handling across the three affected
sites: in
src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs:29-37, make
the save listener async, await putTranslationPrefs, and route failures through
handleError; in
src/public/parts/shells/chat/public/hub/memberContextMenu.mjs:138-147, await
renderMemberList and pass kick, status-refresh, and redraw failures to
handleError; in
src/public/parts/shells/chat/public/hub/messages/render/translation.mjs:42-45,
stop swallowing translation and preference-read failures and use the
corresponding handleError handlers.

In `@src/public/parts/shells/chat/public/src/endpoints/channelArchive.mjs`:
- Around line 91-94: 修改 channelArchive 端点中处理 data.events
的逻辑,移除将非数组值替换为空数组的兜底行为,直接返回契约字段 data.events;响应数据损坏时应让契约错误暴露,而不是伪装成空历史。

In `@src/public/parts/shells/chat/public/src/groupSettings/membersTab.mjs`:
- Around line 18-26: Update kickMember so kickMemberRequest, the success toast,
and context.reload run inside a try block; catch request or reload rejections
and pass them to handleError with the appropriate message key. Ensure failures
do not show the success toast or reload state, and attach catch handling for any
floating async event-dispatch promise as required.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 0e4a7148-5e07-43fd-aab0-5adec65d6008

📥 Commits

Reviewing files that changed from the base of the PR and between dd2c993 and 4a10205.

📒 Files selected for processing (138)
  • src/public/parts/shells/chat/public/AGENTS.md
  • src/public/parts/shells/chat/public/emoji-packs/index.mjs
  • src/public/parts/shells/chat/public/hub/AGENTS.md
  • src/public/parts/shells/chat/public/hub/banners.mjs
  • src/public/parts/shells/chat/public/hub/call.mjs
  • src/public/parts/shells/chat/public/hub/channelContextMenu.mjs
  • src/public/parts/shells/chat/public/hub/charCard.mjs
  • src/public/parts/shells/chat/public/hub/chatConfig.mjs
  • src/public/parts/shells/chat/public/hub/core/bindings.mjs
  • src/public/parts/shells/chat/public/hub/discoveryPanel.mjs
  • src/public/parts/shells/chat/public/hub/entityProfile.mjs
  • src/public/parts/shells/chat/public/hub/federation/federationModal.mjs
  • src/public/parts/shells/chat/public/hub/federation/forkActions.mjs
  • src/public/parts/shells/chat/public/hub/files.mjs
  • src/public/parts/shells/chat/public/hub/friendChat.mjs
  • src/public/parts/shells/chat/public/hub/friendsList.mjs
  • src/public/parts/shells/chat/public/hub/gestures/chatGestures.mjs
  • src/public/parts/shells/chat/public/hub/groupContextMenu.mjs
  • src/public/parts/shells/chat/public/hub/hashNav.mjs
  • src/public/parts/shells/chat/public/hub/hubStatus.mjs
  • src/public/parts/shells/chat/public/hub/inboxClient.mjs
  • src/public/parts/shells/chat/public/hub/inboxView.mjs
  • src/public/parts/shells/chat/public/hub/index.mjs
  • src/public/parts/shells/chat/public/hub/init.mjs
  • src/public/parts/shells/chat/public/hub/initCore.mjs
  • src/public/parts/shells/chat/public/hub/memberContextMenu.mjs
  • src/public/parts/shells/chat/public/hub/memberReadMarkers.mjs
  • src/public/parts/shells/chat/public/hub/mentionAutocomplete.mjs
  • src/public/parts/shells/chat/public/hub/messages/actions/bookmark.mjs
  • src/public/parts/shells/chat/public/hub/messages/actions/branch.mjs
  • src/public/parts/shells/chat/public/hub/messages/actions/delete.mjs
  • src/public/parts/shells/chat/public/hub/messages/actions/edit.mjs
  • src/public/parts/shells/chat/public/hub/messages/actions/feedback.mjs
  • src/public/parts/shells/chat/public/hub/messages/actions/forward.mjs
  • src/public/parts/shells/chat/public/hub/messages/actions/pin.mjs
  • src/public/parts/shells/chat/public/hub/messages/channelMessageStore.mjs
  • src/public/parts/shells/chat/public/hub/messages/channelTypeRouter.mjs
  • src/public/parts/shells/chat/public/hub/messages/exportHtml.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageSend.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs
  • src/public/parts/shells/chat/public/hub/messages/render/translation.mjs
  • src/public/parts/shells/chat/public/hub/misc.mjs
  • src/public/parts/shells/chat/public/hub/personalFilter.mjs
  • src/public/parts/shells/chat/public/hub/pinsBookmarks.mjs
  • src/public/parts/shells/chat/public/hub/presence.mjs
  • src/public/parts/shells/chat/public/hub/privateGroup.mjs
  • src/public/parts/shells/chat/public/hub/profileEdit.mjs
  • src/public/parts/shells/chat/public/hub/runHubAction.mjs
  • src/public/parts/shells/chat/public/hub/search.mjs
  • src/public/parts/shells/chat/public/hub/sendQueue.mjs
  • src/public/parts/shells/chat/public/hub/serverBar.mjs
  • src/public/parts/shells/chat/public/hub/sidebar/createChannel.mjs
  • src/public/parts/shells/chat/public/hub/sidebar/federationRoom.mjs
  • src/public/parts/shells/chat/public/hub/sidebar/groupMembership.mjs
  • src/public/parts/shells/chat/public/hub/sidebar/index.mjs
  • src/public/parts/shells/chat/public/hub/sidebar/selectChannel.mjs
  • src/public/parts/shells/chat/public/hub/stream/handlers/dagEvent.mjs
  • src/public/parts/shells/chat/public/hub/stream/volatileSlots.mjs
  • src/public/parts/shells/chat/public/hub/threadDrawer.mjs
  • src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs
  • src/public/parts/shells/chat/public/hub/unread.mjs
  • src/public/parts/shells/chat/public/hub/wiring/fileEvents.mjs
  • src/public/parts/shells/chat/public/hub/wiring/messageBubbleEvents.mjs
  • src/public/parts/shells/chat/public/hub/wiring/voteEvents.mjs
  • src/public/parts/shells/chat/public/profile/index.mjs
  • src/public/parts/shells/chat/public/profile/ownerSettingsPanel.mjs
  • src/public/parts/shells/chat/public/profile/src/endpoints.mjs
  • src/public/parts/shells/chat/public/providers/emoji.mjs
  • src/public/parts/shells/chat/public/shared/aliases.mjs
  • src/public/parts/shells/chat/public/shared/care.mjs
  • src/public/parts/shells/chat/public/shared/entityProfileCard.mjs
  • src/public/parts/shells/chat/public/shared/entityProfileHoverCard.mjs
  • src/public/parts/shells/chat/public/shared/entityProfilePopup.mjs
  • src/public/parts/shells/chat/public/shared/evfsMedia.mjs
  • src/public/parts/shells/chat/public/shared/notificationPreferences.mjs
  • src/public/parts/shells/chat/public/src/api/channelArchive.mjs
  • src/public/parts/shells/chat/public/src/api/federationSettings.mjs
  • src/public/parts/shells/chat/public/src/api/groupClient.mjs
  • src/public/parts/shells/chat/public/src/auditLogPanel.mjs
  • src/public/parts/shells/chat/public/src/composerAttachments.mjs
  • src/public/parts/shells/chat/public/src/deepLinkConsume.mjs
  • src/public/parts/shells/chat/public/src/dmLink.mjs
  • src/public/parts/shells/chat/public/src/endpoints/channelArchive.mjs
  • src/public/parts/shells/chat/public/src/endpoints/channelPerms.mjs
  • src/public/parts/shells/chat/public/src/endpoints/discovery.mjs
  • src/public/parts/shells/chat/public/src/endpoints/emoji.mjs
  • src/public/parts/shells/chat/public/src/endpoints/emojiPacks.mjs
  • src/public/parts/shells/chat/public/src/endpoints/entities.mjs
  • src/public/parts/shells/chat/public/src/endpoints/federationSettings.mjs
  • src/public/parts/shells/chat/public/src/endpoints/folders.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupBan.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupBookmarks.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupChannel.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupClient.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupCore.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupDm.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupFederation.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupFiles.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupFriendBinding.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs
  • src/public/parts/shells/chat/public/src/endpoints/inbox.mjs
  • src/public/parts/shells/chat/public/src/endpoints/members.mjs
  • src/public/parts/shells/chat/public/src/endpoints/mentions.mjs
  • src/public/parts/shells/chat/public/src/endpoints/p2p.mjs
  • src/public/parts/shells/chat/public/src/endpoints/prefs.mjs
  • src/public/parts/shells/chat/public/src/endpoints/roles.mjs
  • src/public/parts/shells/chat/public/src/endpoints/social.mjs
  • src/public/parts/shells/chat/public/src/endpoints/viewer.mjs
  • src/public/parts/shells/chat/public/src/entityProfileApi.mjs
  • src/public/parts/shells/chat/public/src/files.mjs
  • src/public/parts/shells/chat/public/src/groupFileBlob.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/archiveTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/channelPermsTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/emojisTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/generalTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/inviteTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/load.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/membersTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/permissionsTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/shared.mjs
  • src/public/parts/shells/chat/public/src/groupViewerPermissions.mjs
  • src/public/parts/shells/chat/public/src/lib/personalFilterClient.mjs
  • src/public/parts/shells/chat/public/src/saveStickerFromMessage.mjs
  • src/public/parts/shells/chat/public/src/trustAuthorDialog.mjs
  • src/public/parts/shells/chat/public/src/trustedAuthors.mjs
  • src/public/parts/shells/chat/public/src/ui/errors.mjs
  • src/public/parts/shells/chat/public/src/ui/groupFileUpload.mjs
  • src/public/parts/shells/chat/public/src/ui/groupModals.mjs
  • src/public/parts/shells/chat/public/src/ui/reactionHandlers.mjs
  • src/public/parts/shells/chat/src/chat/dag/chatLogMirror.mjs
  • src/public/parts/shells/chat/src/chat/dag/hydration.mjs
  • src/public/parts/shells/chat/src/chat/federation/bootstrapRelay.mjs
  • src/public/parts/shells/chat/src/chat/federation/index.mjs
  • src/public/parts/shells/chat/src/chat/files/groupFiles.mjs
  • src/public/parts/shells/chat/src/entity/endpoints.mjs
  • src/public/parts/shells/chat/src/group/routes/groupEmojis.mjs
  • src/public/parts/shells/chat/test/pure/viewer_log_dispatch.test.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)
💤 Files with no reviewable changes (7)
  • src/public/parts/shells/chat/public/src/groupSettings/shared.mjs
  • src/public/parts/shells/chat/public/src/ui/errors.mjs
  • src/public/parts/shells/chat/public/src/api/groupClient.mjs
  • src/public/parts/shells/chat/public/src/api/channelArchive.mjs
  • src/public/parts/shells/chat/public/src/api/federationSettings.mjs
  • src/public/parts/shells/chat/public/src/entityProfileApi.mjs
  • src/public/parts/shells/chat/public/profile/src/endpoints.mjs

void refreshChannelPinsBar()
void refreshDagForkBanner().then(() => refreshLocalViewBanner())
refreshChannelPinsBar().catch(handleError('chat.hub.operationFailed'))
refreshDagForkBanner().then(refreshLocalViewBanner).catch(handleError('chat.hub.operationFailed'))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

统一两处 MJS 异步错误边界。

这两处变更继续使用 Promise 链。项目要求异步代码统一使用 async/await,并在异步边界集中处理错误。

  • src/public/parts/shells/chat/public/hub/banners.mjs#L170-L170: 将 refreshLocalViewBanner() 放入带 try/catch 的异步辅助函数,并等待 refreshDagForkBanner()
  • src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs#L353-L355: 用 try/catchawait import(...)await fetchMemberReadMarkers(...) 替换 .then(...).catch(...)

As per coding guidelines,MJS 异步代码必须统一使用 async/await
As per path instructions,异步失败必须通过统一的 handleError(...) 处理。

📍 Affects 2 files
  • src/public/parts/shells/chat/public/hub/banners.mjs#L170-L170 (this comment)
  • src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs#L353-L355
🤖 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/public/parts/shells/chat/public/hub/banners.mjs` at line 170, Replace the
Promise chain at src/public/parts/shells/chat/public/hub/banners.mjs:170-170
with an async helper using try/catch, await refreshDagForkBanner(), then await
refreshLocalViewBanner(), and route failures through
handleError('chat.hub.operationFailed'). Also replace the .then(...).catch(...)
chain at
src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs:353-355 with
try/catch using await import(...) and await fetchMemberReadMarkers(...),
handling errors through the existing handleError(...) mechanism.

Sources: Coding guidelines, Path instructions

Comment thread src/public/parts/shells/chat/public/hub/call.mjs Outdated
Comment thread src/public/parts/shells/chat/public/hub/files.mjs Outdated
Comment thread src/public/parts/shells/chat/public/hub/friendsList.mjs
Comment thread src/public/parts/shells/chat/public/hub/hubStatus.mjs Outdated
Comment thread src/public/parts/shells/chat/public/src/groupSettings/permissionsTab.mjs Outdated
Comment thread src/public/parts/shells/chat/public/src/groupViewerPermissions.mjs Outdated
Comment thread src/public/parts/shells/chat/public/src/lib/personalFilterClient.mjs Outdated
Comment thread src/public/parts/shells/chat/public/src/ui/groupFileUpload.mjs Outdated
Comment thread src/public/parts/shells/chat/test/pure/viewer_log_dispatch.test.mjs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/public/parts/shells/chat/public/hub/chatConfig.mjs (1)

68-68: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

不要静默吞掉插件列表请求失败。

listGroupPlugins(groupId) 失败后会显示不完整的插件配置,但不会报告故障。保留空数组回退时,先调用 handleError

🤖 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/public/parts/shells/chat/public/hub/chatConfig.mjs` at line 68, Update
the listGroupPlugins(groupId) rejection handler to call handleError with the
request error before returning the existing empty-array fallback. Preserve the
current fallback behavior while ensuring failures are reported instead of
silently ignored.

Source: Path instructions

src/public/parts/shells/chat/public/src/api/groupGovernance.mjs (1)

33-45: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

删除这个旧 API 客户端。

此模块直接调用 shell REST,并与 src/endpoints/groupGovernance.mjsblockUser 重复。删除 src/api/groupGovernance.mjs,并让所有调用方直接导入 endpoint 模块。不要保留转发层。

As per path instructions, “keep REST requests behind named functions in public/src/endpoints; UI and other consumers should not call shell REST directly or import the removed public/src/api clients.”

🤖 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/public/parts/shells/chat/public/src/api/groupGovernance.mjs` around lines
33 - 45, 删除 public/src/api/groupGovernance.mjs 及其旧 API 客户端导出;将所有 blockUser
调用方改为直接导入并使用 public/src/endpoints/groupGovernance.mjs 中的同名函数,移除任何转发层或对 shell
REST 的直接调用。

Source: Path instructions

src/public/parts/shells/chat/public/src/groupSettings/membersTab.mjs (1)

41-53: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

将动态导入放入 try 块。

await import('../endpoints/groupBan.mjs')try 块外。模块加载失败时,handleError 不会执行。点击事件的异步回调会产生未处理 rejection。

建议修改
-	const { banMemberWithScope } = await import('../endpoints/groupBan.mjs')
  try {
+		const { banMemberWithScope } = await import('../endpoints/groupBan.mjs')
 		const result = await banMemberWithScope(context.groupId, username, picked)

As per path instructions, “avoid silent catches or unhandled floating promises.”

🤖 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/public/parts/shells/chat/public/src/groupSettings/membersTab.mjs` around
lines 41 - 53, 将 membersTab.mjs 中执行 ban 操作的逻辑调整为把动态导入 ../endpoints/groupBan.mjs
放入现有 try 块内,确保模块加载失败时也通过 handleError('chat.group.settings.page.banFailed')
处理,并避免异步点击回调产生未处理 rejection;保持 pickBanScope 及其取消返回逻辑不变。

Source: Path instructions

🤖 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/public/parts/shells/chat/public/emoji-packs/index.mjs`:
- Line 33: Update the click handler’s Promise chain around onClick so
synchronous exceptions are captured: defer invoking onClick until inside the
promise chain rather than evaluating it as an argument to Promise.resolve, while
preserving the existing handleError('chat.emoji.previewActionFailed') rejection
handling.

In `@src/public/parts/shells/chat/public/hub/composerDraft.mjs`:
- Around line 57-64: 在 composerDraft 的清理逻辑中,将变量 cw 重命名为 contentWarningInput,将 sm
重命名为 sensitiveMediaInput,并将 extras 重命名为 composerExtras;同步更新各自的引用,保持现有行为不变。

In `@src/public/parts/shells/chat/public/hub/messages/render/file.mjs`:
- Around line 23-29: Update loadGroupFileBlobUrl and the media rendering cleanup
flow so every Object URL returned by fetchGroupFileAsBlobUrl is tracked and
revoked when its associated image, inline media, or lazy-loaded media node is
removed or the message is destroyed. Ensure rerenders and virtual-list unmounts
release all tracked URLs via URL.revokeObjectURL, including URLs created before
load failures or replacement content.

In `@src/public/parts/shells/chat/public/hub/personalFilter.mjs`:
- Around line 23-31: Update the error path around fetchPersonalFilterSets so a
failed request does not replace cachedFilter with
normalizePersonalFilterResponse() and expose previously filtered members.
Preserve the centralized handleError('chat.hub.operationFailed') handling, then
either rethrow the error or retain the existing cachedFilter instead of
returning an empty filter set.

In `@src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs`:
- Around line 34-37: 内联一次性使用的临时绑定:在
src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs#L34-L37 中移除
checked 变量,将 `#auto-translate` 的 checked 表达式直接写入 putTranslationPrefs 的 payload;在
src/public/parts/shells/chat/public/src/endpoints/groupClient.mjs#L28-L35
中移除仅使用一次的 headers 绑定,将条件 headers 表达式直接写入 fetch 初始化参数。
- Around line 19-23: Replace the Promise catch chain around getTranslationPrefs
in the translation preferences flow with a try/catch using async/await
exclusively. Preserve the existing handleError('chat.hub.operationFailed')
invocation and the fallback prefs value with autoTranslate disabled, while
keeping the subsequent data.prefs fallback behavior unchanged.

In `@src/public/parts/shells/chat/public/src/deepLinkConsume.mjs`:
- Line 78: 将 applyChatRunUri 中 getViewer() 的 Promise .catch() 链改为 try/catch,并在
catch 中调用 handleError('chat.hub.operationFailed')(error);捕获失败时仍将 viewer 回退为
{},其余流程保持不变。

In `@src/public/parts/shells/chat/public/src/endpoints/entities.mjs`:
- Around line 28-29: Inline the single-use queryString binding in both fetch URL
constructions: src/public/parts/shells/chat/public/src/endpoints/entities.mjs
lines 28-29 and 40-44. Directly call localeQueryString(groupId) when
constructing each optional query-string segment, preserving the existing URL
behavior.

In `@src/public/parts/shells/chat/public/src/endpoints/groupCore.mjs`:
- Around line 203-205: Update listGroupChars so it returns the direct response
from groupFetch without converting non-array values to an empty array. Preserve
the endpoint response as-is, allowing invalid role-list data to propagate and
prevent ensureCharOnGroup from continuing to add a character.

In `@src/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs`:
- Around line 34-36: 为导出函数补充有意义的一行中文 JSDoc 摘要:在
src/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs:34-36 的
blockUser 文档标签前,说明其写入 denylist 条目;在
src/public/parts/shells/chat/public/src/groupFileBlob.mjs:13-15
的对应导出函数文档标签前,说明群文件转换为 Blob URL 的方式。

In `@src/public/parts/shells/chat/src/api/client/privateState.mjs`:
- Around line 35-56: Update the private-state add/remove methods to trust their
API inputs: replace optional chaining and String fallback coercion with direct
reads of entry.groupId, entry.eventId, and entry.href. Ensure calls missing
required fields fail before any deduplication or persistence, so invalid inputs
cannot write private state.
- Around line 33-60: 让 bookmarks 的 add/remove 通过 loader 或 setter
提供的单次原子写操作完成读改写,避免在 ns.list() 与 ns.set() 之间暴露无锁窗口导致并发更新互相覆盖。更新 add 和 remove
方法,复用现有的单次 write API 计算并持久化 entries,同时保留重复追加与未匹配删除时的 added/removed
返回行为;不要继续组合独立的 list()/set() 调用。

In `@src/public/parts/shells/chat/src/endpoints/preferences.mjs`:
- Around line 29-35: 移除书签添加和删除处理器中对 req.body.entry 的空对象回退,直接将 req.body.entry 传递给
client.bookmarks.add 和 client.bookmarks.remove,使缺少 entry 的请求按实际契约失败。

In `@src/public/parts/shells/chat/test/integration/entity_private_state.test.mjs`:
- Around line 56-63: Rename the duplicate bookmark result variable from dup to
duplicate in this test, and update its assertions to use duplicate so the test
state is immediately readable.

---

Outside diff comments:
In `@src/public/parts/shells/chat/public/hub/chatConfig.mjs`:
- Line 68: Update the listGroupPlugins(groupId) rejection handler to call
handleError with the request error before returning the existing empty-array
fallback. Preserve the current fallback behavior while ensuring failures are
reported instead of silently ignored.

In `@src/public/parts/shells/chat/public/src/api/groupGovernance.mjs`:
- Around line 33-45: 删除 public/src/api/groupGovernance.mjs 及其旧 API 客户端导出;将所有
blockUser 调用方改为直接导入并使用 public/src/endpoints/groupGovernance.mjs 中的同名函数,移除任何转发层或对
shell REST 的直接调用。

In `@src/public/parts/shells/chat/public/src/groupSettings/membersTab.mjs`:
- Around line 41-53: 将 membersTab.mjs 中执行 ban 操作的逻辑调整为把动态导入
../endpoints/groupBan.mjs 放入现有 try 块内,确保模块加载失败时也通过
handleError('chat.group.settings.page.banFailed') 处理,并避免异步点击回调产生未处理 rejection;保持
pickBanScope 及其取消返回逻辑不变。
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 2c7dd2fb-90b9-469c-acd8-e4cd21851fe1

📥 Commits

Reviewing files that changed from the base of the PR and between 4a10205 and 2d89cec.

📒 Files selected for processing (56)
  • src/public/parts/shells/chat/public/emoji-packs/index.mjs
  • src/public/parts/shells/chat/public/hub/call.mjs
  • src/public/parts/shells/chat/public/hub/chatConfig.mjs
  • src/public/parts/shells/chat/public/hub/composerDraft.mjs
  • src/public/parts/shells/chat/public/hub/core/bindings.mjs
  • src/public/parts/shells/chat/public/hub/files.mjs
  • src/public/parts/shells/chat/public/hub/friendChat.mjs
  • src/public/parts/shells/chat/public/hub/friendsList.mjs
  • src/public/parts/shells/chat/public/hub/hubStatus.mjs
  • src/public/parts/shells/chat/public/hub/inboxClient.mjs
  • src/public/parts/shells/chat/public/hub/inboxView.mjs
  • src/public/parts/shells/chat/public/hub/initCore.mjs
  • src/public/parts/shells/chat/public/hub/memberContextMenu.mjs
  • src/public/parts/shells/chat/public/hub/memberReadMarkers.mjs
  • src/public/parts/shells/chat/public/hub/mentionAutocomplete.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs
  • src/public/parts/shells/chat/public/hub/messages/render/file.mjs
  • src/public/parts/shells/chat/public/hub/messages/render/translation.mjs
  • src/public/parts/shells/chat/public/hub/misc.mjs
  • src/public/parts/shells/chat/public/hub/personalFilter.mjs
  • src/public/parts/shells/chat/public/hub/profileEdit.mjs
  • src/public/parts/shells/chat/public/hub/serverBar.mjs
  • src/public/parts/shells/chat/public/hub/sidebar/groupMembership.mjs
  • src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs
  • src/public/parts/shells/chat/public/hub/unread.mjs
  • src/public/parts/shells/chat/public/profile/index.mjs
  • src/public/parts/shells/chat/public/profile/ownerSettingsPanel.mjs
  • src/public/parts/shells/chat/public/providers/emoji.mjs
  • src/public/parts/shells/chat/public/src/api/groupBan.mjs
  • src/public/parts/shells/chat/public/src/api/groupBookmarks.mjs
  • src/public/parts/shells/chat/public/src/api/groupGovernance.mjs
  • src/public/parts/shells/chat/public/src/deepLinkConsume.mjs
  • src/public/parts/shells/chat/public/src/endpoints/emoji.mjs
  • src/public/parts/shells/chat/public/src/endpoints/entities.mjs
  • src/public/parts/shells/chat/public/src/endpoints/federationSettings.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupBan.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupBookmarks.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupClient.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupCore.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs
  • src/public/parts/shells/chat/public/src/endpoints/p2p.mjs
  • src/public/parts/shells/chat/public/src/endpoints/prefs.mjs
  • src/public/parts/shells/chat/public/src/groupFileBlob.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/channelPermsTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/emojisTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/membersTab.mjs
  • src/public/parts/shells/chat/public/src/groupSettings/permissionsTab.mjs
  • src/public/parts/shells/chat/public/src/groupViewerPermissions.mjs
  • src/public/parts/shells/chat/public/src/lib/personalFilterClient.mjs
  • src/public/parts/shells/chat/public/src/ui/groupFileUpload.mjs
  • src/public/parts/shells/chat/src/api/client/privateState.mjs
  • src/public/parts/shells/chat/src/endpoints/preferences.mjs
  • src/public/parts/shells/chat/src/group/routes/governance.mjs
  • src/public/parts/shells/chat/test/integration/entity_private_state.test.mjs
  • src/public/parts/shells/chat/test/pure/viewer_log_dispatch.test.mjs
  • src/public/parts/shells/social/public/src/media.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)
💤 Files with no reviewable changes (2)
  • src/public/parts/shells/chat/public/src/api/groupBookmarks.mjs
  • src/public/parts/shells/chat/public/src/api/groupBan.mjs

Comment thread src/public/parts/shells/chat/public/emoji-packs/index.mjs Outdated
Comment thread src/public/parts/shells/chat/public/hub/composerDraft.mjs Outdated
Comment thread src/public/parts/shells/chat/public/hub/messages/render/file.mjs
Comment thread src/public/parts/shells/chat/public/hub/personalFilter.mjs
Comment thread src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs Outdated
Comment on lines +34 to +36
* @param {{ scope: string, value: string, groupId?: string }} entry 拉黑条目
* @returns {Promise<void>}
*/

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

补齐导出函数的中文 JSDoc 摘要。

这两处只有标签,没有有意义的一行摘要。

  • src/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs#L34-L36: 在标签前添加说明 blockUser 写入 denylist 条目的中文摘要。
  • src/public/parts/shells/chat/public/src/groupFileBlob.mjs#L13-L15: 在标签前添加说明群文件如何转换为 Blob URL 的中文摘要。

As per coding guidelines, “write a meaningful one-line JSDoc comment.” Based on learnings, “ensure JSDoc summaries are written in Chinese rather than as pure English.”

📍 Affects 2 files
  • src/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs#L34-L36 (this comment)
  • src/public/parts/shells/chat/public/src/groupFileBlob.mjs#L13-L15
🤖 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/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs` around
lines 34 - 36, 为导出函数补充有意义的一行中文 JSDoc 摘要:在
src/public/parts/shells/chat/public/src/endpoints/groupGovernance.mjs:34-36 的
blockUser 文档标签前,说明其写入 denylist 条目;在
src/public/parts/shells/chat/public/src/groupFileBlob.mjs:13-15
的对应导出函数文档标签前,说明群文件转换为 Blob URL 的方式。

Sources: Coding guidelines, Learnings

Comment thread src/public/parts/shells/chat/src/api/client/privateState.mjs Outdated
Comment on lines +35 to +56
const groupId = String(entry?.groupId || '')
const eventId = String(entry?.eventId || '')
if (groupId && eventId && entries.some(bookmark => bookmark?.groupId === groupId && bookmark?.eventId === eventId))
return { entries, added: false }
entries.push(entry)
const next = await ns.set({ entries })
return { entries: next.entries, added: true }
},
/**
* 原子删除(eventId 优先,回落 href)。
* @param {{ groupId?: string, eventId?: string, href?: string }} entry 匹配条件
* @returns {Promise<{ entries: object[], removed: boolean }>} 写入后列表与是否删除
*/
async remove(entry) {
const { entries } = await ns.list()
const groupId = String(entry?.groupId || '')
const eventId = String(entry?.eventId || '')
const href = String(entry?.href || '')
const next = entries.filter(bookmark => {
if (eventId) return !(String(bookmark?.groupId || '') === groupId && String(bookmark?.eventId || '') === eventId)
if (href) return String(bookmark?.href || '') !== href
return true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

删除受信任 API 的输入兜底。

entry?.String(... || '') 会把无效调用转换为持久化操作。缺失 groupIdeventId 时,add 会绕过去重并写入条目。直接读取 entry.groupIdentry.eventIdentry.href。无效调用应失败,不应写入私有状态。

As per path instructions, “前后端互信;后端信任本机加载的文件” and “类型盘问与防御性编程是坏味道”。

🤖 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/public/parts/shells/chat/src/api/client/privateState.mjs` around lines 35
- 56, Update the private-state add/remove methods to trust their API inputs:
replace optional chaining and String fallback coercion with direct reads of
entry.groupId, entry.eventId, and entry.href. Ensure calls missing required
fields fail before any deduplication or persistence, so invalid inputs cannot
write private state.

Source: Path instructions

Comment thread src/public/parts/shells/chat/src/endpoints/preferences.mjs Outdated
Comment thread src/public/parts/shells/chat/test/integration/entity_private_state.test.mjs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 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/public/parts/shells/chat/public/emoji-packs/index.mjs`:
- Line 33: Replace the Promise chain at
src/public/parts/shells/chat/public/emoji-packs/index.mjs#L33-L33 with an async
click callback that wraps onClick() in try/catch and preserves
handleError('chat.emoji.previewActionFailed') for both synchronous and
asynchronous failures. At
src/public/parts/shells/chat/public/hub/chatConfig.mjs#L68-L71, move
listGroupPlugins failure handling into try/catch and remove .catch(...),
preserving the existing error behavior.

In `@src/public/parts/shells/chat/public/hub/chatConfig.mjs`:
- Around line 68-71: 更新 chatConfig.mjs 中 listGroupPlugins 的失败处理,不要将读取异常转换为
[],应保留失败状态并阻止可编辑插件列表继续渲染。检查依赖该结果的 initial.pluginlist 回退逻辑及 availablePlugins
计算,避免未知状态被当作空的已启用列表;若必须继续显示面板,明确使用已读取的 initial.pluginlist 作为数据源。

In `@src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs`:
- Around line 29-30: 为导出的 destroyChannelVirtualList 函数补充一行有意义的中文 JSDoc
摘要,明确说明其销毁聊天频道虚拟列表的职责,并保留现有的 `@returns` {void} 标注。

In `@src/public/parts/shells/chat/public/hub/messages/render/file.mjs`:
- Around line 185-190: Update the cleanup binding after
placeholder.replaceWith(node) to call bindBlobUrlCleanup on the replacement’s
parent container rather than node itself, so the querySelectorAll scan includes
the newly inserted media node and revokes its blob URL when removed.

In `@src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs`:
- Around line 19-27: Remove the single-use data binding in the translation
preferences flow. Initialize prefs to the default, assign
getTranslationPrefs().prefs directly within the try block while preserving the
fallback when prefs is absent, and keep the existing handleError call and
failure default behavior in the catch block.

In `@src/public/parts/shells/chat/src/api/client/helpers.mjs`:
- Line 12: 为 createShellJsonNamespace 和 createChatShellJsonNamespace 的 JSDoc
注释各添加一行有意义的中文摘要,准确说明其创建对应 JSON 命名空间的用途;保留现有的 `@returns` 标签及其内容不变。
- Line 41: 在 mutator 处理逻辑中移除 current || {} 的防御性回退,直接将 mutator(current) 的返回值传给
shape。保留现有的 shape 和存储写回流程,让 null、undefined 或其他非法返回值按 mutator 的 object 契约在边界处失败。
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 96137350-2664-409c-8a28-739dd3fd7df5

📥 Commits

Reviewing files that changed from the base of the PR and between 2d89cec and 1d89fbe.

📒 Files selected for processing (15)
  • src/public/parts/shells/chat/public/emoji-packs/index.mjs
  • src/public/parts/shells/chat/public/hub/chatConfig.mjs
  • src/public/parts/shells/chat/public/hub/composerDraft.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs
  • src/public/parts/shells/chat/public/hub/messages/render/file.mjs
  • src/public/parts/shells/chat/public/hub/personalFilter.mjs
  • src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs
  • src/public/parts/shells/chat/public/src/deepLinkConsume.mjs
  • src/public/parts/shells/chat/public/src/endpoints/entities.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupClient.mjs
  • src/public/parts/shells/chat/public/src/endpoints/groupCore.mjs
  • src/public/parts/shells/chat/src/api/client/helpers.mjs
  • src/public/parts/shells/chat/src/api/client/privateState.mjs
  • src/public/parts/shells/chat/src/endpoints/preferences.mjs
  • src/public/parts/shells/chat/test/integration/entity_private_state.test.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)

Comment thread src/public/parts/shells/chat/public/emoji-packs/index.mjs Outdated
Comment thread src/public/parts/shells/chat/public/hub/chatConfig.mjs Outdated
Comment thread src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs Outdated
Comment thread src/public/parts/shells/chat/public/hub/messages/render/file.mjs Outdated
Comment thread src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs Outdated
* @param {string} dataName setting 名
* @param {(stored: object) => object} shape 读出规范化;set 时写入该对象
* @returns {{ list: Function, set: Function }} list/set 命名空间
* @returns {{ list: Function, set: Function, update: Function }} list/set/update 命名空间

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

补上两个 JSON 命名空间的 JSDoc 摘要。

createShellJsonNamespacecreateChatShellJsonNamespace 的注释只有 @returns 标签。添加一行有意义的中文摘要,并保留现有标签。

建议修改
 /**
+ * 创建实体 shell 的 JSON 读写命名空间。
  * `@returns` {{ list: Function, set: Function, update: Function }} list/set/update 命名空间
@@
 /**
+ * 创建 Chat shell 的 JSON 读写命名空间。
  * `@returns` {{ list: Function, set: Function, update: Function }} list/set/update 命名空间

根据编码规范,受 jsdoc/require-jsdoc 约束的声明必须包含有意义的一行 JSDoc 摘要。

Also applies to: 53-53

🤖 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/public/parts/shells/chat/src/api/client/helpers.mjs` at line 12, 为
createShellJsonNamespace 和 createChatShellJsonNamespace 的 JSDoc
注释各添加一行有意义的中文摘要,准确说明其创建对应 JSON 命名空间的用途;保留现有的 `@returns` 标签及其内容不变。

Source: Coding guidelines

Comment thread src/public/parts/shells/chat/src/api/client/helpers.mjs Outdated
@steve02081504

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Repository owner deleted a comment from coderabbitai Bot Aug 7, 2026
@steve02081504

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Head commit changed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@steve02081504

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/public/parts/shells/chat/public/hub/messages/render/file.mjs (1)

165-190: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

在媒体模板渲染失败时撤销 Blob URL。

loadGroupFileBlobUrl 成功后,blobUrl 已进入跟踪集合。renderTemplateAsHtmlStringcreateDocumentFragmentFromHtmlStringNoScriptActivation 任一 await 拒绝时,当前流程没有 try/catch。这会留下未处理 rejection,且不会撤销 URL。占位符还会保持原状,重复点击会继续分配 URL。

将渲染和替换流程放入 try/catchcatch 中先调用 revokeTrackedBlobUrl(blobUrl),再交给现有的 handleError

依据代码规范,异步代码必须使用 async/await,并将 Hub 异步失败交给集中式错误处理器。

🤖 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/public/parts/shells/chat/public/hub/messages/render/file.mjs` around
lines 165 - 190, Wrap the media rendering and placeholder replacement flow after
loadGroupFileBlobUrl in a try/catch. In the catch block, first call
revokeTrackedBlobUrl(blobUrl), then pass the error to the existing handleError;
preserve the current missing-URL and missing-node paths, and keep the
async/await style.

Sources: Coding guidelines, Path instructions

src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs (1)

27-37: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

撤销当前频道加载的群文件 Blob URL。

destroyChannelVirtualList() 调用全量 revokeAllGroupFileBlobUrls(),但 trackedBlobUrls 没有区分群/频道;只要当前群存在跨频道消息,切换频道时刚渲染过的 Blob URL 会被一并撤销,后续懒加载替换后无法播放。改为撤销当前频道加载的 URL,或让 URL 生命周期明确绑定到可见内容/当前频道。

🤖 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/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs`
around lines 27 - 37, Update destroyChannelVirtualList so it revokes only Blob
URLs belonging to the channel being destroyed, rather than calling
revokeAllGroupFileBlobUrls for every tracked URL. Adjust the tracking and
cleanup functions in render/file.mjs to associate URLs with their channel and
preserve URLs still needed by messages from other channels.
🤖 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/public/parts/shells/chat/public/hub/chatConfig.mjs`:
- Around line 68-72: Update the plugin list assignment in the chat configuration
flow to use the array returned by listGroupPlugins(groupId) directly: replace
the Array.isArray fallback around activePlugins with direct assignment, while
leaving the charlist handling unchanged.

---

Outside diff comments:
In `@src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs`:
- Around line 27-37: Update destroyChannelVirtualList so it revokes only Blob
URLs belonging to the channel being destroyed, rather than calling
revokeAllGroupFileBlobUrls for every tracked URL. Adjust the tracking and
cleanup functions in render/file.mjs to associate URLs with their channel and
preserve URLs still needed by messages from other channels.

In `@src/public/parts/shells/chat/public/hub/messages/render/file.mjs`:
- Around line 165-190: Wrap the media rendering and placeholder replacement flow
after loadGroupFileBlobUrl in a try/catch. In the catch block, first call
revokeTrackedBlobUrl(blobUrl), then pass the error to the existing handleError;
preserve the current missing-URL and missing-node paths, and keep the
async/await style.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: c6f92f53-b585-47d8-a67f-aeeec02e245c

📥 Commits

Reviewing files that changed from the base of the PR and between 1d89fbe and c1e71bc.

📒 Files selected for processing (6)
  • src/public/parts/shells/chat/public/emoji-packs/index.mjs
  • src/public/parts/shells/chat/public/hub/chatConfig.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs
  • src/public/parts/shells/chat/public/hub/messages/render/file.mjs
  • src/public/parts/shells/chat/public/hub/translationPrefsDialog.mjs
  • src/public/parts/shells/chat/src/api/client/helpers.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)

Comment thread src/public/parts/shells/chat/public/hub/chatConfig.mjs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/public/parts/shells/chat/public/hub/messages/render/file.mjs`:
- Around line 212-214: Update the catch block around revokeTrackedBlobUrl in the
file-rendering flow to invoke the returned handler from
handleError('chat.hub.file.loadFailed') with error, matching the established
pattern used near Line 88; preserve Blob URL cleanup before reporting the
failure.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 04e30847-e355-4606-b8bb-087fdc831042

📥 Commits

Reviewing files that changed from the base of the PR and between c1e71bc and 6646885.

📒 Files selected for processing (4)
  • src/public/parts/shells/chat/public/hub/chatConfig.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs
  • src/public/parts/shells/chat/public/hub/messages/render/file.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)

Comment thread src/public/parts/shells/chat/public/hub/messages/render/file.mjs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 23

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/public/parts/shells/chat/public/hub/chatConfig.mjs (1)

150-159: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

停止在 input 事件中并发保存频率。

拖动滑块会连续触发多个异步请求。请求可以乱序完成。服务端可能保存旧值。

改用 change 事件。这样只保存用户提交后的最终值。

建议修改
-			slider.addEventListener('input', async inputEvent => {
+			slider.addEventListener('change', async inputEvent => {
🤖 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/public/parts/shells/chat/public/hub/chatConfig.mjs` around lines 150 -
159, Change the listener in the slider frequency-saving flow from the input
event to the change event, keeping the existing target lookup, frequency
conversion, setGroupCharFrequency call, and error handling unchanged so only the
final submitted value is saved.
🤖 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/public/locales/ar-SA.json`:
- Line 783: Update the closeSidebar translation in the Arabic locale to use the
requested Arabic text “إغلاق الشريط الجانبي” instead of the English fallback.

In `@src/public/locales/de-DE.json`:
- Line 783: 将德语本地化键 closeSidebar 的英文占位值翻译为自然、准确的德语短语,保持 JSON 结构和键名不变。

In `@src/public/locales/emoji.json`:
- Line 783: Update the closeSidebar entry in the emoji locale to remove the
English text and use an emoji-based translation such as ✖️📋.

In `@src/public/locales/es-ES.json`:
- Line 783: Update the closeSidebar translation in the Spanish locale so the
value is “Cerrar barra lateral” instead of English, preserving the
home.closeSidebar key.
- Line 4716: Correct the Spanish translation for the openCabinets localization
entry by replacing the misspelled “archivoes” with “archivos,” resulting in
“Abrir lista de archivos”.

In `@src/public/locales/fr-FR.json`:
- Line 783: Translate the closeSidebar value in the French locale to the
appropriate French phrase, replacing the English placeholder while preserving
the existing key and JSON structure.

In `@src/public/locales/hi-IN.json`:
- Line 783: Update the home.closeSidebar translation in the Hindi locale to use
the provided Hindi text “साइडबार बंद करें” instead of the English fallback.

In `@src/public/locales/is-IS.json`:
- Line 783: Translate the closeSidebar value in the Icelandic locale to natural
Icelandic UI text, replacing the English placeholder while preserving the
existing key and JSON structure.

In `@src/public/locales/it-IT.json`:
- Line 783: Update the home.closeSidebar locale entry from the English text to
the Italian translation “Chiudi la barra laterale”.
- Line 1968: 在 src/public/locales/it-IT.json 的 1968-1968 行,将 "close" 的值从
"Vicino" 改为 "Chiudi";同时在 4717-4717 行,将 "closeCabinets" 的值从 "Vicino" 改为 "Chiudi"。

In `@src/public/locales/ja-JP.json`:
- Line 783: Update the home.closeSidebar translation value in ja-JP.json from
the English text to the Japanese string サイドバーを閉じる, leaving the key and
surrounding locale entries unchanged.
- Line 1968: Remove the duplicate chat.close entry from the locale data and
update its consumers to reference util.common.close instead. Ensure all
close-label lookups use the shared util.common translation key.

In `@src/public/locales/ko-KR.json`:
- Line 783: Update the home.closeSidebar translation in ko-KR.json from the
English text to the Korean label “사이드바 닫기”.
- Line 1968: Update the "close" entries at both referenced locations in the
Korean locale to use the UI button label "닫기" instead of "폐쇄".

In `@src/public/locales/lzh.json`:
- Line 783: Update the closeSidebar entry in the lzh locale from the English
text to an appropriate Literary Chinese translation, preserving the existing
localization key and JSON structure.

In `@src/public/locales/nl-NL.json`:
- Line 783: Update the closeSidebar translation in the nl-NL locale from the
English text to the Dutch value "Zijbalk sluiten".
- Line 1968: 删除 shell 专属节点中的 chat.close 通用翻译键,并更新其引用以复用 util.common.close;保留已有的
util.common.close(“Sluiten”)作为唯一共享关闭文案。

In `@src/public/locales/pt-PT.json`:
- Line 783: Translate the closeSidebar value in the Portuguese (pt-PT) locale
from the English placeholder to the appropriate Portuguese text for “Close
sidebar,” while keeping the existing key unchanged.

In `@src/public/locales/ru-RU.json`:
- Line 783: 将俄语本地化键 closeSidebar 的英文占位值替换为准确的俄语“关闭侧边栏”翻译,保持其他本地化内容不变。

In `@src/public/locales/uk-UA.json`:
- Line 783: Update the closeSidebar locale entry in uk-UA.json by replacing the
English placeholder “Close sidebar” with the correct Ukrainian translation,
leaving the key unchanged.

In `@src/public/locales/vi-VN.json`:
- Line 1968: Update the Vietnamese translation values for chat.hub.close at
src/public/locales/vi-VN.json:1968-1968 and cabinet.closeCabinets at
src/public/locales/vi-VN.json:4717-4717 from the door-closing wording to “Đóng”
for consistent UI close actions.
- Line 783: Update the closeSidebar translation in the Vietnamese locale from
English to the project’s standard Vietnamese wording, using “Đóng thanh bên” if
no existing convention applies.

In `@src/public/locales/zh-TW.json`:
- Line 782: Update the closeSidebar translation entry in zh-TW to use the
appropriate Traditional Chinese translation instead of the English text.

---

Outside diff comments:
In `@src/public/parts/shells/chat/public/hub/chatConfig.mjs`:
- Around line 150-159: Change the listener in the slider frequency-saving flow
from the input event to the change event, keeping the existing target lookup,
frequency conversion, setGroupCharFrequency call, and error handling unchanged
so only the final submitted value is saved.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: ee5ee942-ded9-471b-ae2f-b139a182d40d

📥 Commits

Reviewing files that changed from the base of the PR and between c1e71bc and 277af45.

📒 Files selected for processing (29)
  • src/decl/locale_data.ts
  • src/public/locales/ar-SA.json
  • src/public/locales/de-DE.json
  • src/public/locales/emoji.json
  • src/public/locales/en-UK.json
  • src/public/locales/es-ES.json
  • src/public/locales/fr-FR.json
  • src/public/locales/hi-IN.json
  • src/public/locales/is-IS.json
  • src/public/locales/it-IT.json
  • src/public/locales/ja-JP.json
  • src/public/locales/ko-KR.json
  • src/public/locales/lzh.json
  • src/public/locales/nl-NL.json
  • src/public/locales/pt-PT.json
  • src/public/locales/ru-RU.json
  • src/public/locales/uk-UA.json
  • src/public/locales/vi-VN.json
  • src/public/locales/zh-CN.json
  • src/public/locales/zh-TW.json
  • src/public/pages/i18n-notes.md
  • src/public/parts/shells/cabinet/public/index.html
  • src/public/parts/shells/chat/public/hub/chatConfig.mjs
  • src/public/parts/shells/chat/public/hub/index.html
  • src/public/parts/shells/chat/public/hub/messages/messageRefresh.mjs
  • src/public/parts/shells/chat/public/hub/messages/messageVirtualList.mjs
  • src/public/parts/shells/chat/public/hub/messages/render/file.mjs
  • src/public/parts/shells/home/public/index.html
  • src/public/parts/shells/social/public/index.html
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)

Comment thread src/public/locales/ar-SA.json Outdated
Comment thread src/public/locales/de-DE.json Outdated
Comment thread src/public/locales/emoji.json Outdated
Comment thread src/public/locales/es-ES.json Outdated
"title": "Inicio",
"description": "El corazón de tu experiencia en fount. Aquí, gestiona los habitantes de tu imaginación: personajes, mundos y personas. Tus historias comienzan y se ramifican a partir de este nexo central.",
"sidebarTitle": "Detalles",
"closeSidebar": "Close sidebar",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

home.closeSidebar 翻译为西语。

当前值会在西语界面显示英语。改为 "Cerrar barra lateral"

🤖 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/public/locales/es-ES.json` at line 783, Update the closeSidebar
translation in the Spanish locale so the value is “Cerrar barra lateral” instead
of English, preserving the home.closeSidebar key.

Comment thread src/public/locales/es-ES.json Outdated
"title": "Cerrar",
"aria-label": "Cerrar"
},
"openCabinets": "Abrir lista de archivoes",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

修正 openCabinets 的西语文本。

archivoes 是拼写错误。改为 "Abrir lista de archivos"

🤖 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/public/locales/es-ES.json` at line 4716, Correct the Spanish translation
for the openCabinets localization entry by replacing the misspelled “archivoes”
with “archivos,” resulting in “Abrir lista de archivos”.

Comment thread src/public/locales/ru-RU.json Outdated
Comment thread src/public/locales/uk-UA.json Outdated
Comment thread src/public/locales/vi-VN.json Outdated
Comment thread src/public/locales/vi-VN.json Outdated
Comment thread src/public/locales/zh-TW.json Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/public/parts/shells/chat/public/hub/chatConfig.mjs (1)

68-72: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

删除一次性临时绑定。

activePlugins 只用于初始化 pluginlistfrequency 只用于一次请求。直接绑定最终值,减少无意义的跳转。

依据路径规范“禁止只用一次的临时绑定,内联到使用处”。

建议修改
-		const [initial, worlds, personas, allPlugins, activePlugins] = await Promise.all([
+		const [initial, worlds, personas, allPlugins, pluginlist] = await Promise.all([
 			getGroupChatConfig(groupId),
 			getPartList('worlds').catch(() => []),
 			getPartList('personas').catch(() => []),
 			getPartList('plugins').catch(() => []),
 			listGroupPlugins(groupId),
 		])
 
 		const charlist = Array.isArray(initial?.charlist) ? initial.charlist : []
-		const pluginlist = activePlugins
 		const freqMap = initial?.frequency_data || {}
...
-				const frequency = Number(changeEvent.target.value) / 100
 				try {
-					await setGroupCharFrequency(groupId, charname, frequency)
+					await setGroupCharFrequency(groupId, charname, Number(changeEvent.target.value) / 100)

Also applies to: 150-159

🤖 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/public/parts/shells/chat/public/hub/chatConfig.mjs` around lines 68 - 72,
Remove the one-time temporary bindings around charlist, pluginlist, and
frequency in the chat configuration flow, including the additionally referenced
section, and inline their final expressions directly at their use sites.
Preserve the existing fallback and request behavior while eliminating
intermediate variables that are consumed only once.

Source: Path instructions

🤖 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/public/locales/de-DE.json`:
- Line 1968: Remove the chat.close locale entry and update its callers to use
the existing util.common.close key for the shared “Schließen” label. Keep shared
text under util.* and preserve shell-specific keys only for shell-specific copy.

In `@src/public/locales/lzh.json`:
- Line 783: Update the closeSidebar translation in lzh.json from simplified
characters to the locale’s traditional forms, using “闔側欄” to match the file’s
existing wording.

In `@src/public/locales/uk-UA.json`:
- Line 1968: Remove the duplicate close entry from the chat locale section and
update its consumers to read the shared util.common.close translation instead.
Preserve the existing Ukrainian text through the util.common.close entry.

In `@src/public/locales/zh-TW.json`:
- Line 1967: 删除 locale 文件中的 chat.hub.close 键,复用现有的 util.common.close
文案;保持调用方通过共享键访问“关闭”翻译,并确保 util.* 下的共享文案不被重复定义。

---

Outside diff comments:
In `@src/public/parts/shells/chat/public/hub/chatConfig.mjs`:
- Around line 68-72: Remove the one-time temporary bindings around charlist,
pluginlist, and frequency in the chat configuration flow, including the
additionally referenced section, and inline their final expressions directly at
their use sites. Preserve the existing fallback and request behavior while
eliminating intermediate variables that are consumed only once.
🪄 Autofix

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: ASSERTIVE

Plan: Pro Plus

Run ID: 731b96d1-5621-434a-9254-cde185fa872a

📥 Commits

Reviewing files that changed from the base of the PR and between 277af45 and bbf4051.

📒 Files selected for processing (19)
  • src/public/locales/ar-SA.json
  • src/public/locales/de-DE.json
  • src/public/locales/emoji.json
  • src/public/locales/es-ES.json
  • src/public/locales/fr-FR.json
  • src/public/locales/hi-IN.json
  • src/public/locales/is-IS.json
  • src/public/locales/it-IT.json
  • src/public/locales/ja-JP.json
  • src/public/locales/ko-KR.json
  • src/public/locales/lzh.json
  • src/public/locales/nl-NL.json
  • src/public/locales/pt-PT.json
  • src/public/locales/ru-RU.json
  • src/public/locales/uk-UA.json
  • src/public/locales/vi-VN.json
  • src/public/locales/zh-CN.json
  • src/public/locales/zh-TW.json
  • src/public/parts/shells/chat/public/hub/chatConfig.mjs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • steve02081504/fount-p2p (manual)

Comment thread src/public/locales/de-DE.json Outdated
"ariaClose": {
"aria-label": "Schließen"
},
"close": "Schließen",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

删除 chat.close,复用已有公共键。

chat.close 只是通用的“Schließen”。文件的 Line 5667 已有 util.common.close。保留这个键会重复文案,并违反 locale 约定。将调用方改为 util.common.close,然后删除 Line 1968 的键。

As per path instructions: 共享文案必须放在 util.*;shell-specific copy 才放在 shell 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/public/locales/de-DE.json` at line 1968, Remove the chat.close locale
entry and update its callers to use the existing util.common.close key for the
shared “Schließen” label. Keep shared text under util.* and preserve
shell-specific keys only for shell-specific copy.

Source: Path instructions

Comment thread src/public/locales/lzh.json Outdated
Comment thread src/public/locales/uk-UA.json Outdated
Comment thread src/public/locales/zh-TW.json Outdated
@steve02081504
steve02081504 merged commit fdc0123 into master Aug 7, 2026
3 of 4 checks passed
@steve02081504
steve02081504 deleted the split/chat branch August 7, 2026 15:17
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.

3 participants