Repository navigation
TB-300: 人工筛选并移植 fork 截止 1dd4b0a 的非 Preview 改动 - #140
Conversation
* fix(ohos): align bundle identifier with Harmony debug profile * fix(ohos): accept Huawei debug profile identifier in CLI (cherry picked from commit 979eddb)
Bundle one 1933-byte original EPUB without images or fonts. Import and delete it explicitly from developer settings using existing offline storage and reader flows. Keep sample shelf actions and reading progress local; cover persistence, retries, concurrent import/deletion, and native cleanup. (cherry picked from commit 1dd4b0a)
Manually extract stable configurations and regression coverage from hehetoshang/moke ba5a9fe. Exclude Preview configuration and runtime.
Extract generic app-name configuration support from hehetoshang/moke 8490772. Adapt the test to an ordinary custom product name; exclude Preview identity and release changes.
| }, [selectedIds, batchMode]); | ||
|
|
||
| // ── Single-item actions (from right-click / long-press menu) ──────────── | ||
| const updateShelf = async (id: string) => { |
There was a problem hiding this comment.
新增的 state.wants 在离线书架里会被丢弃。
同文件 src/app/shelf/page.tsx:208-211 是:
buildOfflineLibrary(records.filter((record) => record.inShelf === true)).map((record) => ({
...record,
state: { download: 1 }, // ← 整体覆盖,wants 没了
}))buildOfflineLibrary 在本 PR 里新增了 state: { wants }(src/lib/offline-library.ts:10,19,34),但这里用 { download: 1 } 把整个 state 覆盖掉,结果 BookTable 的「在书架」徽标(BookTable.tsx:282)和 wants 排序(BookTable.tsx:96)在离线书架中永远为 falsy。离线书架的 canRemoveShelf 菜单项本身是写死的 移出书架,所以功能不受影响,但状态显示不一致,且本 PR 新增的字段在三个消费方里只有一个半生效(library/page 和 search/page 生效,shelf/page 不生效)。
建议改成保留已有 state:
state: { ...record.state, download: 1 },| } | ||
| return records | ||
| .filter((record) => !serverUrl || sameServer(record.serverUrl, serverUrl)) | ||
| .filter((record) => !serverUrl || sameServer(record.serverUrl, serverUrl) || isSampleBook(record)) |
There was a problem hiding this comment.
|| isSampleBook(record) 让示例书对任意 serverUrl 都出现在 listOfflineBooks() 的结果里。除了预期的离线书架 / 离线书库 / 离线搜索,它还会流到:
src/app/downloads/page.tsx:89→ 「下载管理」在每个服务器下都会列出内置示例书;src/app/detail/page.tsx:198→ 本地记录按bookId匹配(示例书 ID 是固定字符串,不会误命中 Talebook 数字 ID,风险低)。
我确认过写入路径都用 sameServer 收窄:getOfflineBook、setOfflineBookShelfState、deleteOfflineBook、syncOfflineDownloadState 都不会因为跨服务器可见而误改/误删别的服务器数据(新测试也覆盖了这点),所以这里不是数据隔离漏洞。只是请确认「下载管理里每个服务器都显示示例书」是预期产品行为;如果不是,筛选条件可能需要再收一层(例如只在 offline mode 或首次导入时返回)。
| } | ||
|
|
||
| export async function fetchReadingProgress(bookId: string | number, signal?: AbortSignal): Promise<ReadingProgressPayload | null> { | ||
| if (bookId === SAMPLE_BOOK.bookId) return null; |
There was a problem hiding this comment.
示例书的阅读进度在 Moke 这一侧被完全丢弃:fetchReadingProgress 返回 null,saveReadingProgress(第 92 行)直接 return。这样确实不会把内置书写进 Talebook 的 /readstate,但 Moke 也不再有示例书的任何进度来源。
ReaderProgressProvider.tsx 是唯一的上报入口(事件 → saveReadingProgress),所以请确认 readest 自身会按 mokeBookId 落盘、重新打开能续读;否则示例书每次都会从头开始,而 openOfflineBook 里 restoreProgress 恒为 null 会让这个现象很难排查。
另外这里对 bookId: string | number 直接用 === 比较字符串常量,只有内置 ID 会命中,建议补一句注释说明「仅内置示例书,避免与服务器书籍 ID 混淆」,与 sample-book-info.ts 里的约定保持一致。
| .to_string(), | ||
| ) | ||
| .with_status_code(503); | ||
| let _ = request.respond(response); |
There was a problem hiding this comment.
这里有两个小问题:
- 缺少 CORS 头:正常错误路径(
respond_api_error)以及 401 / health 响应都会带cors_header,只有这个新增的 503 没带。对浏览器扩展来说,跨源请求会变成不透明的 CORS 失败,而不是能读到SERVER_BUSY正文的 503。建议直接复用respond_api_error(request, ApiError{status:503, code:"SERVER_BUSY", ...}, cors_header)。 - 在 accept 线程里同步回写:正常请求路径是
thread::spawn(move || handle_request(...)),而这个 503 是直接在 accept 循环里调用request.respond()写 socket。响应体很小、通常能进内核发送缓冲,但如果对端不读,写仍可能阻塞,从而卡住整个 accept 循环(正好是这个 PR 想避免的那类问题)。建议放进独立线程,或与 32 个 slot 一样由有界线程池处理。
| if !matches!(method, tiny_http::Method::Post | tiny_http::Method::Put) { | ||
| return Ok(None); | ||
| } | ||
| let declared = declared |
There was a problem hiding this comment.
两层限流本身没问题(先看 Content-Length、读取时再 take(MAX+1) 兜底,容量按 declared.min(MAX) 预分配也对)。但这里引入了一个行为变化需要确认:
- 强制要求 Content-Length:用 chunked transfer-encoding 上传的 POST/PUT(
fetch传ReadableStream、部分 HTTP 客户端/代理默认分块)会直接拿到 411。如果扩展协议里存在流式请求体,这是破坏性变更;如果不存在,建议在扩展 API 文档里写明「必须先给出 Content-Length」。 - 非 POST/PUT 不读正文:
validate_declared_body_length对其他方法返回Ok(None),正文既不被读取也不被消费。当前路由里 DELETE 不用 body,所以没有实际问题,但 DELETE 带 body 会被静默忽略——这点值得在文档或注释里显式说明,否则以后加路由时很容易踩。
| "$schema": "https://schema.tauri.app/config/2", | ||
| "productName": "Moke", | ||
| "identifier": "org.houheya.moke", | ||
| "identifier": "org.houheya.moke_openharmony", |
There was a problem hiding this comment.
应用身份变更需要谨慎对待:
houheya是 fork 作者的个人命名空间,稳定版长期沿用这个反域名建议再确认一次(是否应该用 talebook 自己的命名空间)。审计文档也把这点列为待 QA 结论。- 这是应用身份变化,不只是显示名:旧稳定包(
org.houheya.moke)→ 新包(org.houheya.moke_openharmony)的直接升级、数据保留、以及与 Preview 共存都还没做设备验证(PR 描述已列为待验证项)。在拿到结论前不建议进入发布。 - 该字符串在
.github/workflows/build-release.yml:548的断言里又硬编码了一遍,两处必须同步修改,否则发布会在断言步骤失败。
另外确认一下:为这一个标识符在 Tauri CLI 里开下划线例外,是否会和华为 Profile 校验或其他平台(Android/iOS)的标识符规则产生冲突。
| .any(|ch| !(ch.is_alphanumeric() || ch == '-' || ch == '.')) | ||
| {`; | ||
| const replacement = ` // Huawei OpenHarmony debug profiles may use this app-specific underscore. | ||
| if config.identifier != "org.houheya.moke_openharmony" |
There was a problem hiding this comment.
这个 patch 把标识符硬编码进脚本,和 src-tauri/tauri.ohos.conf.json 形成隐式耦合:
- 一旦配置里的包名改了(比如去掉
houheya),CLI 的例外不会生效,只会在构建时报「identifier 非法」——属于 fail-closed,但排查成本高。建议从tauri.ohos.conf.json读取标识符,或至少在脚本里显式断言配置值等于这个常量。 - 脚本会就地修改
vendor/tauri子模块(writeFileSync(sourcePath, ...)),在 CI 里会让子模块工作区变脏。目前后续步骤看起来不依赖干净子模块,但若以后有git submodule update/ 清洁性检查步骤就会冲突,建议在注释里写明这一点(幂等性本身由测试覆盖了,这点没问题)。
| @@ -0,0 +1,65 @@ | |||
| import { test, expect } from '@playwright/test'; | |||
There was a problem hiding this comment.
这个 Playwright spec 目前不会在 CI 里执行:
.github/workflows/ci.yml:167只显式传了tests/responsive-smoke.spec.mjs tests/captcha-sandbox.spec.mjs;- 仓库里没有
playwright.config.*,所以没有testDir之类的默认发现规则; - 根
pnpm test只匹配tests/*.test.mjs,也覆盖不到.spec.mjs。
PR 描述把示例书的 UI 验证主要归在这个文件(导入/刷新持久化/删除/503 重试/键盘 Enter)。既然它不是 dead code 就是 lint 目标之外的文件,建议把它加进 ci.yml 的 playwright 命令行(并确认 CI 环境里有它依赖的 MOKE_E2E_BASE_URL 与已导入的 privacy-consent / developer-storage 初始状态)。
| 'src-tauri/tauri.windows.conf.json', | ||
| ]; | ||
|
|
||
| test('desktop windows remain resizable without a minimum size', () => { |
There was a problem hiding this comment.
两个点:
- 测试把四份桌面配置的路径写死(第 5-10 行)。将来新增桌面/平板配置(仓库里已有
tauri.mobile.conf.json、tauri.tablet.conf.json)不会自动纳入校验,反而会让「没有 minWidth」这个约束悄悄失效。可以考虑用 glob 扫描src-tauri/tauri*.conf.json,或至少把这层意图写进测试名/注释。 - 更想确认产品侧的取舍:完全移除
minWidth/minHeight后桌面窗口可以缩到很小,主界面会不可用(原来的 800×600 是有意的最小值)。如果目的只是为小屏/墨水屏设备放宽限制,建议保留一个更小的下限(例如 480×360),而不是彻底去掉;如果确实要允许任意尺寸,请在 PR 里说明原因。
将 hehetoshang/moke 截止
1dd4b0aa908a4e935fc10dc434c1631519de4a64(包含该提交)的非 Preview 功能移植到稳定版。人工检查 37 个源提交后,在 talebook/moke 最新 main 基线484475e上逐项 cherry-pick 或提取。完整处置理由见 逐提交审计。变更与来源
1dd4b0a:默认不导入的原创示例 EPUB、开发者导入/删除入口、离线书架与本地进度隔离;适配新版 README,保留 upstream 漫画阅读器逻辑。ba5a9fe:手动提取稳定桌面的最小窗口尺寸取消及回归测试,排除 Preview 配置和运行时。5a33e4b:手动提取扩展 REST 并发/正文上限、WS 握手并发/超时/消息上限及 Rust 测试。与已有 fix(security): harden extension API and WebSocket boundary #115 的资源限制有重叠,后续合并需去重;本 PR 不替代其完整 Host/Origin/CORS/token 加固。979eddb:OHOS 华为 Profile 包名修复、单一包名的 CLI 校验例外、显式 OHOS 配置与 HAP 身份断言。未移入签名发布流程。8490772:手动提取 iOS 名称校验对显式构建配置的支持;测试改为普通 Custom 配置,排除 Preview 身份校验。375109b/5a33e4b:手动提取 updater 清单通用校验、参数化及确定性平台选择;稳定 tag、GitHub 下载地址、Darwin 更新及无签名时成功跳过均保留。明确排除 Preview 授权、激活门禁、设备租约/换机、控制平面、受控更新授权、设备凭据、签名分发、Preview 配置/版本策略及 fork 的 CI 豁免。没有整体合并 fork,没有修改版本号或 Reader/vendor gitlink。
验证
pnpm test:481/481 通过。pnpm lint、pnpm typecheck:通过。tests/sample-book.spec.mjs:移动持久化/删除、加载禁用/错误恢复通过;桌面首次导航超时,单独复验通过。此机器使用/usr/bin/chromium和放宽超时的临时配置;标准启动首轮有 Chromium 创建页面超时。node --test tests/updater-manifest.test.mjs:4/4 通过(包含在 481 项内)。rustfmt --check --edition 2021(两个受改动 Rust 模块):通过。实际 vendored Tauri CLI 的 OHOS patch 可应用且幂等。cargo test --lib --locked:首轮缺 vendor 依赖,初始化固定 gitlink 后重试进入编译;因本机空间不足风险(剩余约 3 GB,且共享机器有其他编译)停止本次编译,Rust 测试未完成。待验证与质量门禁
OHOS identifier 从
org.houheya.moke改为org.houheya.moke_openharmony,旧包直接升级、数据保留及与 Preview 共存尚未做设备验证。桌面/移动原生 Reader 打开、返回、文件清理,完整原生构建及 Rust 测试未验证。Draft:等待 Mika 协调 Sol → Grok 在固定 head SHA 首轮评审、统一清单及双模型复核,当前没有两位 QA 的通过结论。此 PR 仅提交可审查实现,不自动批准、合并、发布或部署。
Related TB-300