From e1484f4cc0cb003a1849e2803eb77fd98c1a9cad Mon Sep 17 00:00:00 2001 From: lix-2026 Date: Mon, 25 May 2026 00:57:52 +0800 Subject: [PATCH] refactor: move upload fetch timeout helper --- ...0-browser-runtime-followup-checklist-v1.md | 8 ++++++- ...29-editor-runtime-followup-checklist-v1.md | 5 +++- .../mnote-web/browser/local-upload-runtime.js | 23 +++++++++++++++++++ rust/crates/mnote-web/src/ssr/pages/layout.rs | 5 ++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/design/03-rust-web/process/3-20-browser-runtime-followup-checklist-v1.md b/design/03-rust-web/process/3-20-browser-runtime-followup-checklist-v1.md index 4564199a..3c78b9fa 100644 --- a/design/03-rust-web/process/3-20-browser-runtime-followup-checklist-v1.md +++ b/design/03-rust-web/process/3-20-browser-runtime-followup-checklist-v1.md @@ -6,7 +6,7 @@ ## 1. 目标 -在 `3-19` 已归档的基础上,继续把仍留在 Rust inline / 主壳大 runtime 中的浏览器行为切成可审计模块。Codex 维护本文件作为事实源,Reasonix 只承接短批次审计、窄范围实现或浏览器 smoke;每批最多 2 个 worker。 +在 `3-19` 已归档的基础上,继续把仍留在 Rust inline / 主壳大 runtime 中的浏览器行为切成可审计模块。Codex 维护本文件作为事实源,Reasonix 只承接短批次审计、窄范围实现或浏览器 smoke;每批最多 4 个 worker。 ## 2. 本轮边界 @@ -65,3 +65,9 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据 - 2026-05-25:Codex 创建本续跑事实源。 - 2026-05-25:修正执行约束:本文件遵循当前 goal 的“每批最多 2 个 worker”,不再沿用早期草稿中的 4 worker 并行方案。 - 2026-05-25:下一批只派发 Worker B(local upload / filetree 下一刀只读审计);Worker A/C/D 暂缓。 +- 2026-05-25:Reasonix local upload / filetree 只读审计尝试未产生 `result.json` / `process-handoff`,且运行期间出现额外 Batch A2 runner,主控已终止进程;该结果不作为正式 handoff 采纳。 + - 可参考的 transcript 结论:`fetchWithTimeout` 是低风险纯工具函数,可先迁入 `local-upload-runtime.js`;`uploadFileToMediaAsset` / `uploadFilesWithResolvedTarget` / `insertUploadedAssetIntoEditor` 仍与 API、editor 插入和 snapshot refresh 耦合,暂不迁。 +- 2026-05-25:Codex 主控直接完成低风险切片:`local-upload-runtime.js` 新增并导出 `fetchWithTimeout`,`layout.rs` 的 inline `fetchWithTimeout` 先委托 runtime,保留原 fallback。 + - 修改:`rust/crates/mnote-web/browser/local-upload-runtime.js`、`rust/crates/mnote-web/src/ssr/pages/layout.rs`。 + - 已验证:`node --check rust/crates/mnote-web/browser/local-upload-runtime.js`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/Cargo.toml -p mnote-web`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web mnote_browser_runtime_assets_are_explicitly_mounted -- --test-threads=1`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web local_upload_runtime_contains_editor_upload_context_helpers -- --test-threads=1`。 + - 未完成:`insertUploadedAssetIntoEditor`、`uploadFileToMediaAsset`、`uploadFilesWithResolvedTarget` 仍未迁出。 diff --git a/design/05-editor-mainline/process/5-29-editor-runtime-followup-checklist-v1.md b/design/05-editor-mainline/process/5-29-editor-runtime-followup-checklist-v1.md index 9f89159c..c5680c31 100644 --- a/design/05-editor-mainline/process/5-29-editor-runtime-followup-checklist-v1.md +++ b/design/05-editor-mainline/process/5-29-editor-runtime-followup-checklist-v1.md @@ -67,4 +67,7 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据 - 已迁函数:`node_is_within_root`、`active_editor_text_selection`、`has_active_text_selection`、`selection_summary`、`selection_has_rich_marks`。 - 未迁:`SelectionPayload`、`selection_payload`、`send_selection_state*`、`selection_event_payload`,原因是仍依赖 bridge event、`HoveredBlockState` 和 runtime block id 边界。 - 已验证:`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/spikes/leptos-tiptap-spike/Cargo.toml`、wasm release build、`wasm-bindgen`、`task488`、`task489`、CodeGraph pending 0。 -- 2026-05-25:下一批只派发 Worker B(overlay / block menu 只读审计);Worker C/D 暂缓,避免超过每批最多 2 个 worker 的 goal 约束。 +- 2026-05-25:执行口径修正:用户指出只读审计推进过慢,后续 B/C/D 应使用独立 worktree 产出候选 patch,而不是只读审计;每批最多 4 个 worker。 +- 2026-05-25:Reasonix runner 异常:后续实现 run 未写 `result.json`、`process-handoff.md/json`,部分 transcript 停在工具调用阶段;Codex 不采纳其文字结论,只复核实际 diff。 +- 2026-05-25:Reasonix overlay / block menu 只读审计尝试未产生 `result.json` / `process-handoff`,且运行期间出现额外 Batch A2 runner,主控已终止进程;该结果不作为正式 handoff 采纳。 + - transcript 只显示探索过程,未形成函数归属表;下一次应改为更窄的单问题只读任务,例如只审计 `floating_toolbar_anchor_from_selection` / `sync_text_selection_overlay` 能否迁入 `overlays.rs`。 diff --git a/rust/crates/mnote-web/browser/local-upload-runtime.js b/rust/crates/mnote-web/browser/local-upload-runtime.js index 0508d7d7..33b91be9 100644 --- a/rust/crates/mnote-web/browser/local-upload-runtime.js +++ b/rust/crates/mnote-web/browser/local-upload-runtime.js @@ -124,6 +124,28 @@ function openEditorUploadFilePicker(detail, deps) { input.click(); } +async function fetchWithTimeout(input, init, timeoutMs, label) { + var controller = typeof AbortController === 'function' ? new AbortController() : null; + var timer = 0; + try { + if (controller) { + timer = window.setTimeout(function() { + controller.abort(); + }, Math.max(1000, Number(timeoutMs) || 15000)); + } + var nextInit = Object.assign({}, init || {}); + if (controller) nextInit.signal = controller.signal; + return await fetch(input, nextInit); + } catch (error) { + if (error && error.name === 'AbortError') { + throw new Error((label || '请求') + '超时'); + } + throw error; + } finally { + if (timer) window.clearTimeout(timer); + } +} + function localAssetOpenUrl(asset, download, context) { if (!isLocalUploadedAsset(asset)) return ''; var rootUri = String(context && context.rootUri || asset && (asset.rootUri || asset.root_uri) || '').trim() || currentRootUri(); @@ -252,6 +274,7 @@ window.__mnoteLocalUploadRuntime = { resolveEditorUploadContext: resolveEditorUploadContext, editorRootFromUploadOptions: editorRootFromUploadOptions, openEditorUploadFilePicker: openEditorUploadFilePicker, + fetchWithTimeout: fetchWithTimeout, localAssetOpenUrl: localAssetOpenUrl, uploadedAssetType: uploadedAssetType, fileTreeIconKindForFileName: fileTreeIconKindForFileName, diff --git a/rust/crates/mnote-web/src/ssr/pages/layout.rs b/rust/crates/mnote-web/src/ssr/pages/layout.rs index bee5c9eb..5eef2295 100644 --- a/rust/crates/mnote-web/src/ssr/pages/layout.rs +++ b/rust/crates/mnote-web/src/ssr/pages/layout.rs @@ -3879,6 +3879,10 @@ const SIDEBAR_TREE_JS: &str = r##" } async function fetchWithTimeout(input, init, timeoutMs, label) { + var runtimeFn = localUploadRuntimeFunction('fetchWithTimeout'); + if (runtimeFn) { + return await runtimeFn(input, init || {}, timeoutMs, label); + } var controller = typeof AbortController === 'function' ? new AbortController() : null; var timer = 0; try { @@ -10930,6 +10934,7 @@ mod tests { assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function resolveEditorUploadContext")); assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function editorRootFromUploadOptions")); assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function openEditorUploadFilePicker")); + assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function fetchWithTimeout")); assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("uploadFilesWithResolvedTarget")); assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("__mnoteLastEditorUploadRoot")); }