|
|
debe7dabe3
|
fix(test): Docker 集成测试在无 daemon 环境优雅跳过而非失败
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
docker.rs 的 4 个 test_run_in_container_* 此前直接 unwrap Docker 客户端,
在没有 Docker daemon 的环境(如 CI、纯服务端交叉编译检查)会 panic 失败,
拖累整套 cargo test 的退出码——即便这些测试本就无法在那里运行。
加 require_docker() 守卫:socket 缺失(DOCKER_CLIENT == None)或 daemon
无响应(轻量 version() 探测)时返回 None,测试 eprintln + 提前 return。
选动态探测而非 #[ignore]:#[ignore] 会在所有环境一律跳过、需
cargo test --ignored 显式触发;探测守卫让测试在有 Docker 时自动运行,
在无 Docker 的 CI 上静默放行,且在 --nocapture 下可见跳过原因。
验证:cargo test --bin yggdrasil 从 535 passed / 4 failed → 539 passed / 0 failed。
|
2026-07-16 13:22:49 +08:00 |
|
|
|
fa8b1d9968
|
test: 补齐安全关键路径的单元测试盲区
针对前期测试评估发现的高性价比纯函数与安全不变量盲区补测,
共新增 35 个回归测试(全部通过),分布如下:
- infra/docker.rs (+5): 扩展 build_host_config 的隔离断言——cap_drop=ALL、
security_opt=no-new-privileges、pids_limit=64、memory_swap==memory(禁 swap)、
tmpfs 的 exec 仅落在 /tmp、ulimits 只保留 nofile(无 nproc)。这些配置若被
误删会让容器隔离悄悄失效,此前 test_host_config_generation 仅断言 cpu/memory。
- api/code_runner/execute.rs (+8): validate_exec_request 此前零测试。覆盖
语言白名单(大小写/空白容忍、多 token 拒绝、未注册拒绝)、源码大小边界
(恰好 max 放行 / max+1 拒绝)、校验顺序(语言优先于大小)。
- api/database/export.rs (+12): is_simple_ident / parse_source 此前零测试。
覆盖表名白名单(SQL 注入 / 路径穿越 / Unicode 拒绝)、query: 来源的只读
AST 校验(INSERT/UPDATE/DELETE/DROP/TRUNCATE/CREATE/ALTER/GRANT 全拦截)。
- api/sanitizer.rs (+10): 补 XSS 攻击向量回归——事件处理器属性(onerror/onload/
onclick + 大小写混淆)、script/style 连内容移除、iframe/object/svg/form 等
危险标签整体移除、javascript:/vbscript: scheme(含 HTML 实体编码绕过)、
data URI 在文章正文路径(allow_data_uri=false)的拒绝、svg data URI 风险点锁定。
顺带记录一个既有可维护性问题:docker.rs 的 4 个 test_run_in_container_*
依赖真实 Docker daemon,无 daemon 环境会失败而非跳过,建议后续加 #[ignore]
或 daemon 探测守卫。本次未改动它们。
|
2026-07-16 11:55:58 +08:00 |
|
|
|
fdf2243299
|
docs(env): 补全 .env.example 缺失的 5 个环境变量
代码中经 env::var 读取但示例文件遗漏:
- EXPOSE_VERSION_HEADERS (main.rs:232, 安全相关, 控制版本暴露响应头)
- SYSINFO_SAMPLE_SECS (sysinfo_sampler.rs:46, 后台采样间隔)
- CODE_RUNNER_MAX_SOURCE_BYTES (runner_config.rs:67)
- CODE_RUNNER_QUEUE_TIMEOUT_SECS (runner_config.rs:79)
- CODE_RUNNER_TASK_TTL_SECS (runner_config.rs:83)
默认值与代码一致, 注释风格沿用现有分组(安全段 / tuning 段 /
Code Runner 段)。交叉核对确认示例文件无多余项。
|
2026-07-16 11:42:30 +08:00 |
|
|
|
d1c41e8fc5
|
fix(wasm): hooks 模块移出 server gate,双端可见
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
mod hooks 原被 cfg(feature = "server") 包裹,WASM 前端无法引用 hooks 中的
代码。移出后 server 与 WASM 两端均能访问 hooks 模块。
同步修正 backup.rs 的 import 排序(cargo fmt 自动调整)
|
2026-07-16 11:37:13 +08:00 |
|
|
|
5b6cb7d796
|
feat(middleware): COMPRESSION_ALGORITHMS 默认值改为 off
未设置环境变量时不再默认启用全部压缩算法,改为默认关闭。显式设为
"all" 或具体算法组合仍可按需开启。
- src/middleware.rs: fallback 由 "all" 改为 "off",同步更新文档注释
与默认值测试(compression_default_env_is_all → _is_off)
- .env.example: 示例值与说明同步更新
|
2026-07-16 11:33:14 +08:00 |
|
|
|
593c0322bc
|
fix(server): 端口被占用时优雅退出而非 panic
dioxus::server::serve() 内部对 TcpListener::bind 失败直接
unwrap(dioxus-server 0.7.9 launch.rs:143),端口占用会触发
裸 panic + SIGABRT。在迁移完成后、serve() 前先探测同一地址,
失败走统一的 exit(1) 路径并给出可操作的提示(lsof / PORT)。
|
2026-07-16 11:23:45 +08:00 |
|
|
|
c2263e6bf1
|
chore(lint): 修复 rust-1.97 clippy useless_borrows_in_formatting 告警
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
新版 clippy 在 format! 参数的冗余 & 上新增 lint(与 mimalloc 改动无关),
移除 export.rs 的 &table_name 以保持 make lint 零告警。
|
2026-07-16 10:53:59 +08:00 |
|
|
|
5b183007a7
|
perf(server): 用 mimalloc 替换系统全局分配器
多线程高频小对象分配场景下,mimalloc 吞吐显著优于系统 malloc,且对全静态
musl 链接友好(生产 Docker 镜像即 musl 目标)。选 mimalloc 而非 jemalloc:
本项目生产 server 是全静态 musl 二进制,jemalloc 在 musl 上有 pthread_getname_np
(musl<1.2.3)/unprefixed-malloc 符号冲突的已知坑。
cfg 双门控(与项目双目标编译约定一致):
- feature=server:分配器只服务端二进制需要
- not(wasm32):mimalloc_rust 在 wasm32 上无法编译(Issue #76),前端走默认分配器
mimalloc 声明为 optional + 经 server feature 启用,与 argon2/uuid 等 server-only
依赖同栏位。验证:server native + WASM 双目标编译通过 + clippy 零告警。
musl 目标受本机无 musl-gcc 限制,需 Docker 内构建验证(同 zenwebp 等任何 C 依赖)。
|
2026-07-16 10:53:51 +08:00 |
|
|
|
8c907e4c67
|
chore(skill): 移除未使用的 writing-great-skills 技能及其 lock 注册
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
|
2026-07-16 10:29:06 +08:00 |
|
|
|
dc24de0dbb
|
chore: 更新 skills 配置与术语;新增 rust-advanced-performance 技能;清理 Makefile
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
|
2026-07-16 10:27:51 +08:00 |
|
|
|
c6cb401522
|
refactor(admin): 拆分 system.rs 为 system/ 目录(按 tab 分文件)
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
pages/admin/system.rs 单文件 1792 行装 5 个 tab(数据库状态/服务器状态/SQL控制台/导出/备份恢复),按已有 api/database/ 的对称模式拆成 system/ 目录。
关键前提(已验证):5 个 tab 状态完全独立、互不共享,切换时父组件用 key 强制卸载,零跨文件状态耦合。
拆分结构(与 api/database/mod.rs 全路径风格对称):
- system/mod.rs: SystemTab enum + System 入口 + format_bytes(pub(super),3 tab 共用) + tests
- system/db_status.rs: DbStatusTab
- system/server_status.rs: ServerStatusTab + format_uptime(仅它用)
- system/sql_console.rs: SqlConsoleTab(codemirror_bridge 依赖)
- system/export.rs: ExportTab + urlencode(wasm32)
- system/backup.rs: BackupTab + BackupRow + urlencode_dl(自包含,不再跨文件依赖 export.rs)
路由侧零改动: admin/mod.rs 的 pub mod system + pub use system::System 不变(Rust 自动认 system/mod.rs)。双目标编译 + clippy 严格 + dx check + SystemTab 测试全部通过。
|
2026-07-15 18:28:39 +08:00 |
|
|
|
110be35c54
|
refactor: 抽 main.rs 中间件到 src/middleware.rs
main.rs 混合了配置校验、压缩层、cache-control、admin guard、迁移 runtime、后台任务、路由注册,其中 5 个 server-only 中间件/纯函数可独立测试。迁出到新建 src/middleware.rs(#![cfg(feature=server)]):CompressionAlgorithms + parse_compression_algorithms + compression_layer_from_env + cache_control_for_path + add_cache_control + admin_guard,连同 12 个单元测试。main.rs 调用点改为全路径 crate::middleware::xxx。无新 crate、无循环依赖。main.rs 756 -> 382 行,中间件现已可独立测试。
|
2026-07-15 18:20:56 +08:00 |
|
|
|
5a88531543
|
refactor(api): 收敛 mod.rs 逐行 allow 为文件级 #![allow]
api/posts/mod.rs(7处) 与 api/comments/mod.rs(3处) 在 pub use 行上方逐行加 #[allow(unused_imports)],而文件顶部已有 #![allow(clippy::unused_unit, deprecated)]。这些 allow 经核实真实必要(消费侧 server fn 多仅在 WASM 路径,SSR 编译时 unused),故收敛为 #![allow(..., unused_imports)] 等价替代,删掉 10 处逐行 attribute。clippy 严格模式 -D warnings 通过。
|
2026-07-15 18:16:49 +08:00 |
|
|
|
5e2365ef7c
|
docs: 补全 xterm-terminal / shared 库说明并修正 libs 数量
AGENTS.md 通篇写 4 个 libs,但实际有 6 个(pnpm workspace): xterm-terminal 已接入(Dioxus.toml + src/xterm_bridge.rs + code_runner/runner.rs),文档未记录; shared 是内部源码共享包(无 public 产物),同样未提。
修正: 各处 4 个 libs 改全部 libs; Frontend Lib Subprojects 表格新增 xterm-terminal 行; 章节导语 Four 改 Five + 注明 shared; Code Runner render layer 补 xterm 终端渲染说明; JS workspace 段补 @yggdrasil/shared 包说明; Makefile build-libs 注释改全部并新增 build-xterm target。
|
2026-07-15 18:15:47 +08:00 |
|
|
|
22d05a98b3
|
chore(lint): 修复 Biome 告警(schema 版本/optional chain/CSS !important 抑制)
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
- biome.json: $schema 2.5.1 → 2.5.3,对齐已安装的 CLI 版本(消除 info)
- code-block-view.ts:157: `a && a.b()` → `a?.b()`(等价 optional chain)
- style.css:56: 保留刻意的 `transform: none !important`(删除会重新引入
animation-fill-mode: both 导致的堆叠上下文 bug),仅加 scoped biome-ignore
抑制 noImportantStyles,不做全局禁用
|
2026-07-15 18:12:04 +08:00 |
|
|
|
27ed605223
|
fix(comments): 修复 section.rs / dashboard.rs 括号不匹配导致编译失败
两处同一类错误:match arm 内 `if {} else {}` 表达式后多了一个 `}`,
导致 arm 被提前关闭,触发 "unexpected closing delimiter" 编译错误。
- section.rs:125 — `if !has_any {…}` 块后多余的 `}`,删除使 if-else 合一
- dashboard.rs:119 — 同类问题,另需补 `;` 终止 `let` 语句
|
2026-07-15 18:12:00 +08:00 |
|
|
|
bdc9f0f711
|
chore(make): fix 目标新增 cargo fmt 与 dx fmt
自动修复流程此前只跑 biome format + cargo fix,缺少格式化收尾:
cargo fix 应用编译器建议会重写代码,dx fmt 会改写 rsx!,
两者都可能留下不符合 rustfmt 风格的输出。
现在按 Biome → cargo fix → cargo fmt → dx fmt 顺序执行,
两道格式化收尾保证最终文件状态整洁。
|
2026-07-15 17:50:00 +08:00 |
|
|
|
886eeca915
|
style: 全项目 rsx! 格式规范化(cargo fmt)
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
|
2026-07-15 17:49:03 +08:00 |
|
|
|
cbb8be7441
|
feat(make): 新增 docker-amd64 与 docker-apple 目标构建 x86_64 镜像
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
docker target 只出当前宿主架构(Apple Silicon 上为 arm64),无法直接得到
x86 镜像;docker-multiarch 虽支持 amd64 但强制 --push 到 registry,无法本地
验证。补两个本地可用的 x86_64 构建 target:
- docker-amd64:docker buildx --platform linux/amd64 --load,走 QEMU 交叉仿真,
产物进 Docker 本地 daemon,可直接 docker run / docker save。
- docker-apple:Apple Container CLI(macos 26 Tahoe)原生构建,无需 Docker Desktop,
用 --arch(非 --platform)。
Dockerfile 本身按 dpkg --print-architecture 自适应选 musl target,无需修改。
|
2026-07-15 17:36:57 +08:00 |
|
|
|
832b7c626d
|
fix(infra): Docker daemon 不可用时不再 panic
DOCKER_CLIENT 是 LazyLock<Docker>,socket 缺失时 .expect() 直接 panic;
而 release profile 是 panic="abort",会让整个服务进程挂掉——但博客本身并不依赖 Docker。
改为 LazyLock<Option<Docker>>:连接失败记 error 日志后存 None。
新增 get_docker() 在 None 时返回 IOError(NotFound),run_in_container /
run_in_container_stream 通过 ? 向上冒泡,最终在 execute.rs 的错误脱敏层映射为
「系统暂时不可用」,其余功能不受影响。
|
2026-07-15 17:23:56 +08:00 |
|
|
|
65a7b1226f
|
style: 全项目格式规范化(cargo fmt)+ Docker daemon 断连容错
- 全项目 .rs 统一 cargo fmt 排版(换行/缩进/参数分行/导入排序)
- infra/docker: DOCKER_CLIENT 连接失败不 panic,降级返回 None
(博客不依赖 Docker,panic=abort 下会导致整个进程崩溃)
- infra/mod: 去除多余空行
- database/mod: 模块声明按字母序重新排序
|
2026-07-15 17:22:06 +08:00 |
|
|
|
71f3351c99
|
feat(server): 通过响应头主动暴露版本与 git 描述信息
新增 version_headers_middleware,为所有响应附加三个头:
- Server: yggdrasil/<version>(遵循 product/version 习惯)
- X-Yggdrasil-Version: Cargo 版本号
- X-Yggdrasil-Git: git describe(版本+提交数+短hash+脏标记)
数据源复用 build_info::BUILD_INFO,与启动日志 log_build_info() 同源,
零新依赖。
关键设计:中间件挂在最终合并 router 的最外层(Ok(router) 前),因此
/healthz、/uploads/*、被 CSRF 拒(403)/超时/admin_guard 重定向的响应
都会带头,探测价值最大。此前 app_routes 的中间件栈只覆盖 Dioxus 路由,
无法覆盖这些端点。
受 EXPOSE_VERSION_HEADERS 控制,默认 true;设 0/false/no 关闭。
bool 解析沿用 COOKIE_SECURE 的 matches!("1"/"true"/"yes") 约定,
此处取反为"非 false 值即开"使默认行为对应「暴露」。启动时记录一条
info 日志便于确认生效值。
|
2026-07-15 17:12:55 +08:00 |
|
|
|
a3ca08f3f6
|
chore(docker): 完善 .dockerignore 规则
原 .dockerignore 仅覆盖 target/.git/node_modules 与部分 public 产物,
遗漏多个会导致上下文膨胀或信息泄露的路径:
- 修复信息泄露: .env(含真实 DATABASE_URL)此前会进入构建上下文
- 新增未忽略的构建产物: public/xterm/、public/doc/
- 排除机器本地/无关目录: others/(55M 引用博客)、.freebsd-sysroot/、
docker/(runner 镜像源,单独构建)、docs/、tests/、scripts/
- 排除 agent/IDE/CI 工具: .zcode/、.superpowers/、.agents/、.gitea/、
.vscode/、.idea/、rust-analyzer.toml 等
- 补充常见本地文件: .DS_Store、*.swp、profile.json.gz、compose*.yaml
保留所有真实构建输入(Cargo.toml、build.rs、Dioxus.toml、input.css、
.cargo/config.toml、src/、migrations/、libs/ 工作区、themes/、syntaxes/
及 public 运行时资源 favicon.ico/icons/images/),已逐一核对。
|
2026-07-15 15:18:13 +08:00 |
|
|
|
62d06fb35d
|
chore(skill): 清理已卸载的第三方 skills 及其 lock 注册
|
2026-07-15 14:32:04 +08:00 |
|
|
|
875dc39b61
|
chore(skill): 补全 skills-lock.json 注册并格式化 SKILL.md 表格
|
2026-07-15 14:21:20 +08:00 |
|
|
|
2d5c7f3d2a
|
style(main): 修复缩进格式与模块/导入排序
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
|
2026-07-15 13:56:43 +08:00 |
|
|
|
acfdfb03f5
|
fix(image): 为 ImageFmt 别名补上 #[cfg(feature = "server")] 门控
type ImageFmt = image::ImageFormat 未加 server feature 门控,
而 image crate 是 server-only 可选依赖。WASM 构建 (web feature)
解析到该别名时找不到 image crate,报 E0433。
detect_format (唯一使用方) 已有 #[cfg(feature = "server")],
测试也在 #[cfg(all(test, feature = "server"))] 下,别名只需对齐门控。
|
2026-07-15 13:30:38 +08:00 |
|
|
|
8efd8c8021
|
perf(image): cache_key 单次拼接 + detect_format 零分配后缀匹配
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
cache_key:旧实现 vec![path.to_string()] + 最多 6 个 format! + join,
最坏 9 次堆分配(path clone + 6 个参数 String + Vec 指针数组 + join String)。
改用 with_capacity + write! 直写,1 次分配。每次未命中缓存的图片请求都走。
detect_format:旧实现对整条路径 to_lowercase() 分配 String,只为查后缀。
改用 rsplit('.').next() 取后缀 + eq_ignore_ascii_case 零分配匹配。
每次图片请求调用 1-2 次。
注:rotate 在 resize 之前是刻意设计(让 w/h 作用于旋转后的最终方向),
不动以保持 URL 语义与缓存一致性。
|
2026-07-15 11:48:59 +08:00 |
|
|
|
b269fcf205
|
perf(posts): list/search 零 capacity Vec 改 collect 预分配 + helpers retain
list.rs 5 处、search.rs 1 处用 Vec::new()+循环 push,初始 capacity 为 0,
循环触发多次指数 realloc。rows.iter().map().collect() 用 slice 迭代器的
精确 size_hint 一次性预分配。首页/列表/搜索/标签分页路径。
helpers.rs row_to_post_list_item / row_to_post_full:tags 从
into_iter().filter().collect() 改 retain 原地过滤。unwrap_or_default()
已返回 owned Vec,旧写法重建第二个 Vec。每行文章记录省一次 Vec 分配。
顺带修 slugify 一个 dead store(prev_dash=false 后被 true 无条件覆盖)。
|
2026-07-15 11:46:56 +08:00 |
|
|
|
a41a1d3ae1
|
perf(markdown): 消除双解析 + format! 改 write! 直写
双解析:旧实现对同一份 md 调两次 Parser::new_ext(一遍收集标题、
一遍生成 HTML),等于两倍的 tokenize + 解析 CPU。现 collect 成
Vec<Event> 一次,两遍遍历复用(Event 内含 CowStr 借用 md 切片,
collect 后仍可重复借用)。解析 CPU 减半。
format! → write!:标题开始/结束、TOC li、runnable pre、language class
共 5 处在循环内用 format! 拼接 HTML 片段,每次先分配临时 String 再
push_str 复制进去、临时串立即丢弃。改用 write!(html, ...) 直写目标
String,零中间分配。N 个标题省约 3N 次临时分配。
顺带:html 与 toc_html 用 with_capacity 预分配(旧 String::new 多次 realloc)。
全部 68 个 markdown 测试通过。
|
2026-07-15 11:41:55 +08:00 |
|
|
|
d4f8b463d2
|
perf(slug): slugify 单遍状态机重写,分配 4→1
旧实现 4 次堆分配、3 遍扫描:
1. title.to_lowercase() 分配整串 String(中文/符号根本不受影响却全量拷)
2. split('-').filter().collect::<Vec<&str>>() 分配 Vec
3. parts.join('-') 再分配 String
4. slug.chars().take(100).collect() 截断又分配
新实现用 prev_dash 状态机在单遍内完成:拼音成词、ASCII 小写化、
分隔符合并去首尾、按 char 截断到 100。1 次预分配、1 遍扫描。
与同仓库 markdown.rs::slugify_heading 的单遍写法对齐。
全部 27 个 slug 测试通过(含拼音边界、连续 dash、首尾 dash、下划线保留)。
|
2026-07-15 11:38:54 +08:00 |
|
|
|
b34f44d3e7
|
perf(html): escape_html 链式 5 次 replace 改单遍扫描
旧实现链式 5 次 str::replace,每次全量扫描 + 分配新 String,
5 个特殊字符 = 5 次堆分配 + 5 遍全文扫描,中间 4 个 String 立即丢弃。
新实现:先按字节快速检测是否含特殊字符(纯文本直接 clone 返回),
否则单遍 match 扫描 + 单次 with_capacity 分配。
分配 5→1(-80%),扫描 5→1。该函数被 markdown 渲染管线密集调用
(每个标题文本、每个 runnable 代码块的 overrides/source 转义)。
|
2026-07-15 11:32:36 +08:00 |
|
|
|
604febde98
|
perf(upload): 消除 data.to_vec() 多次全文件深拷贝
data 是引用计数的 Bytes,clone 廉价(原子 +1)。
- validate 路径:data.to_vec() → data.clone(),省一次全文件拷贝
- 转码闭包:original_data = data.to_vec() → data.clone(),
仅在「保留原格式」回退分支才 to_vec() 出落盘所需 Vec<u8>
- 路径拼接:用 chrono DelayedFormat 内联,省 year/month/day 三个中间 String
5MB 图片上传:转码成功路径从 10MB 堆分配降到 0(仅 Bytes 引用计数);
回退路径从 10MB 降到 5MB。
|
2026-07-15 11:28:21 +08:00 |
|
|
|
0835811487
|
style(header): 调整 nav 高度 80px → 64px (h-16)
|
2026-07-15 11:03:27 +08:00 |
|
|
|
ffa0a72e51
|
feat(admin/posts): tab 栏加平滑滑动指示器动画
PostsTabs 此前用 border-b-2 边框瞬切表示选中态,缺少 tab 切换的滑动动画。
移植 FilterTabs(system/comments 页)的滑动指示器机制:相对定位容器 + 绝对
定位滑块(贴底边盖住外层 border-b),WASM 端测量目标 button 的
offsetLeft/offsetWidth 动态定位,transition-all duration-300 驱动滑块从一个
tab 平滑滑到另一个。
选中态从 border-b-2 边框改为文字颜色区分(text-paper-primary),滑块负责
视觉指示。回收站数量角标保留不变。
与 FilterTabs 视觉一致,但 PostsTabs 因需支持角标故未直接复用 FilterTabs
(后者 items 是纯文本元组)。本地自建 POSTS_TAB_GROUP_ID 计数器给每处实例
唯一 DOM id 前缀。
|
2026-07-15 10:47:31 +08:00 |
|
|
|
50e64cd34c
|
fix(code_runner): use_resolved_theme 从 use_effect 闭包提到 cfg 块顶层
dx check 报 4 处 'hook called in a closure: use_resolved_theme':
use_resolved_theme() 是 hook(内部 use_context),被错误地放在 use_effect 的
move || { ... } 闭包内调用。Dioxus 规则要求 hook 只能在组件渲染路径顶层调用。
修复:在两个 #[cfg(target_arch="wasm32")] 块顶层各调用一次 use_resolved_theme()
拿到 Memo<ResolvedTheme>,move 进下方 effect 闭包;闭包内改为调用 memo
(resolved_theme())读值。调用 memo 本身不是 hook(Memo 是 Copy + Fn),
读值的同时建立主题订阅——主题切换时 effect 仍会重跑,行为不变。
范式对齐 ThemeToggle(src/theme.rs:341)的正确用法。
影响 4 处:CodeMirror 挂载/主题同步 effect、xterm 挂载/主题同步 effect。
|
2026-07-15 10:29:01 +08:00 |
|
|
|
0b40105341
|
feat(skill): 新增 optimizing-rust-performance 性能优化 skill
TDD-for-skills 流程提炼:先跑 baseline(两个 Rust 子代理无 skill 时
一致地「提及但未应用」Cow/SmallVec,且不量化收益、不提 profiling),
再写最小 skill 堵住这些缺口,GREEN 测试确认子代理带上 skill 后实际
应用所有模式并量化收益。
核心内容:
- 固定优先级心智模型(算法→内存→布局→并发)
- 5 个触发→动作模式:swap_remove / retain / take / SmallVec / Cow
- 热点路径额外模式(切片取词素、借用切片匹配、ASCII 谓词)
- 量化收益表 + profiling 提醒规范
- 过度优化防护:新增依赖代价、Cow 返回类型的 API 传染、决策速查表
|
2026-07-15 10:24:20 +08:00 |
|
|
|
25299d266f
|
refactor(admin): 合并 /admin/posts 与 /admin/posts/trash 为单路由 + tab 切换
将「全部文章」与「回收站」从两个独立路由(及各自的分页变体 PostsPage /
PostsTrashPage)合并为单一 /admin/posts 路由,用顶部 tab 在二者间切换。
tab 状态与翻页均改为客户端 signal 驱动(不走路由、不深链),与 system.rs 的
tab 模式一致:admin 内部页,刷新回到「全部文章」第 1 页。
路由瘦身:删除 PostsTrash / PostsTrashPage / PostsPage 三个变体,Router 不再
需要「静态段 trash 优先于 :page」的排序技巧。
主要改动:
- posts.rs: Posts 改为 tab 容器(PostsTab 枚举 + active_tab signal + key 化
match 渲染),header 文案随 tab 切换;PostsPage 主体下沉为 AllPostsList,
翻页改 current_page signal + use_paginated 回调式 Pagination。
- posts_trash.rs: PostsTrashPage → PostsTrashPanel(无参,signal 翻页),
删除入口组件与 PostsTabs import(header/tab 由容器统一提供)。
- PostsTabs: 从路由驱动(use_route)改为 signal 驱动(on_change 回调)。
- 修复 tab 水平对齐 bug:两个 tab 统一 inline-flex items-center 同盒模型 +
外层容器加 items-center,根除原先「全部文章」(inline 文本) 与「回收站」
(inline-flex 带角标) 盒模型不一致导致的垂直错位。
- admin_layout.rs: is_posts_route 简化为只匹配 Route::Posts{}。
- RebuildCacheBar 改为完全自持 state(rebuilding + result),结果消息行随组件
内联渲染,与父组件零耦合。
|
2026-07-15 10:21:50 +08:00 |
|
|
|
51e06cf118
|
refactor(ui): Pagination 支持可选 on_prev/on_next 回调翻页
翻页要本地化(走客户端 signal 而非路由)时,传入 on_prev/on_next 即渲染
button onclick;不传则保持原路由式 Link,前台/其他分页页面零影响。
为合并 /admin/posts 与 /admin/posts/trash 为单路由 tab 做准备:两个 tab
的列表翻页将改为 signal 驱动。prev_route/next_route 改为带默认值
(Route::Home {} 占位),回调存在时不被读取。
|
2026-07-15 10:00:40 +08:00 |
|
|
|
e18d2bfb2c
|
fix(docker): 用 tmpfs mode=1777 替换 uid/gid 选项以兼容 Podman
|
2026-07-14 16:42:04 +08:00 |
|
|
|
af3cd4b525
|
chore: gitignore public/xterm 构建产物
新增 xterm feature 时漏了同步 .gitignore,导致 xterm-terminal 的
vite 构建产物(terminal.{js,css,js.map})被提交进仓库——与其余
4 个 lib(tiptap/codemirror/lightbox/yggdrasil-core)一致,这些
IIFE 产物本就该忽略,源码在 libs/xterm-terminal/src/。
git rm --cached 三个产物文件(磁盘保留),.gitignore 补 public/xterm。
|
2026-07-14 16:36:51 +08:00 |
|
|
|
9bc8b5c2ee
|
refactor(libs): 抽取 @yggdrasil/shared 消除跨 IIFE 库的类型/常量重复
新增 libs/shared 内部包,作为跨 IIFE 库的单一真相源:
- ThemeName 类型(原 codemirror/themes.ts + xterm/themes.ts 各一份)
- THEME_CHANGE_EVENT 常量(原 yggdrasil-core 导出 + codemirror/xterm
各硬编码同名 string literal,靠注释维系一致)
- prefersReducedMotion 函数(原 lightbox + yggdrasil-core 各一份)
codemirror-editor / xterm-terminal / lightbox / yggdrasil-core 四个库
改为 workspace 依赖 @yggdrasil/shared,Vite 构建时 inline 进各自 IIFE,
不破坏 IIFE 隔离。消除「改一处忘改另一处导致静默失效」的风险。
附:image_reader_limits 已在上一提交共享;本提交是 libs 侧的对称改动。
|
2026-07-14 15:39:41 +08:00 |
|
|
|
6837b4cfa2
|
refactor(image): 合并维度读取函数,共享 image_reader_limits
提取 read_webp_dimensions / read_image_dimensions 两个核心函数,
read_dimensions_by_mime 与 read_dimensions_from_bytes 各自只负责
格式映射(MIME→format / 扩展名→format),消除 zenwebp 调用与
into_dimensions 逻辑的双份实现。
附带收紧:read_dimensions_from_bytes 原用 with_guessed_format() 猜测
格式,现改为按扩展名显式匹配,避免猜测错误。
image_reader_limits() 改为 pub(crate),upload.rs 的内联 limits 构造
(4 行逐字重复)改为调用共享函数。
|
2026-07-14 15:13:21 +08:00 |
|
|
|
fade4e180f
|
refactor: 删除死代码 CommentActions 组件
components/comments/actions.rs (CommentActions) 零引用——评论管理
操作(通过/垃圾/删除)已在 pages/admin/comments.rs 用 BTN_SOLID_*
常量实现,actions.rs 是遗留的重复实现。
原计划将它的内联按钮样式提取为 BTN_PILL_* 常量统一,但确认零引用后
直接删除整个文件更干净。trash_comment re-export 补 allow(unused_imports)
(wasm-only import 在 server 构建触发的已知模式)。
|
2026-07-14 15:09:41 +08:00 |
|
|
|
9e57247a2d
|
refactor: 统一 WASM sleep 到 utils::time::sleep_ms
删除 system.rs 的私有 wasm_sleep(与 utils::time::sleep_ms 逐字相同),
6 处调用改用 crate::utils::time::sleep_ms。
ui.rs 的内联 Promise+setTimeout(50ms) 同样替换为 sleep_ms(50)。
消除 3 份 sleep 实现中的 2 份冗余副本,utils::time::sleep_ms 成为全项目
唯一的 sleep 入口(已有 native tokio + WASM 双实现)。
|
2026-07-14 14:55:34 +08:00 |
|
|
|
804bcfb7b7
|
refactor(upload): 抽取 upload_error() 消除 15 处 JSON 错误响应样板
upload.rs 中 14 处 return Err((StatusCode::X, Json(json!({"success":
false, "error": MSG})))) + 1 处 map_err 同款 tuple,全部替换为
upload_error(status, msg) 单行调用。helper 接受 impl Serialize,
兼容 &str / String / 字面量等调用形式。
|
2026-07-14 14:53:18 +08:00 |
|
|
|
8da678b3b4
|
refactor(cache): 抽取 invalidate_post_metadata() 封装 4 行失效组合
文章写操作后总要一起失效 lists/tags/stats/search 四项元数据缓存。
新增 invalidate_post_metadata() 封装这个固定组合,替换 create/delete/
update/trash 中的 8 处重复 4 行序列。
保留定向失效(invalidate_post_by_slug / invalidate_tag_posts_for)
和批量回退路径(invalidate_all_post_caches + invalidate_search_results)
的显式调用——它们是按实际涉及数据细粒度控制的,不应被封装吞掉。
|
2026-07-14 14:44:00 +08:00 |
|
|
|
22750ef89e
|
refactor(api): 为 Response 类型添加构造器,消除 51 处样板
CreatePostResponse 新增 err()/ok()/ok_msg() 构造器,消除 posts/
下 34 处 { success, message, post_id, slug } 字面量构造。
CommentResponse 新增 error()/ok()/created() 构造器,消除 comments/
下 17 处 { success, message, error_code, comment_id, ... } 字面量构造。
构造器只在 server function body 内调用,WASM 端因 cfg gate 剥离了
调用点,故加 #[cfg_attr(not(feature="server"), allow(dead_code))]。
行为完全不变(505 测试全过),代码量净减约 300 行样板。
|
2026-07-14 14:36:56 +08:00 |
|
|
|
16caa7dd9e
|
fix(comments): 统一 escape_html,修复代码块单引号未转义
comments/markdown.rs 的本地 html_escape 只转义 4 个字符(漏单引号),
与规范实现 utils::html::escape_html(5 字符,'→')不一致。
删除本地副本,改用 crate::utils::html::escape_html。评论代码块里的
单引号现在会被正确转义,与其他上下文的转义行为统一。
|
2026-07-14 14:29:53 +08:00 |
|
|
|
b39afbb616
|
refactor: 删除死代码 (delayed_loading.rs / ui.rs EmptyState / 未用 re-export)
- 删除 src/hooks/delayed_loading.rs:未在 hooks/mod.rs 注册,已被
DelayedSkeleton 组件取代(mod.rs 注释已说明)
- 删除 src/components/ui.rs 的 EmptyState:零调用者,所有实际用法
都走功能更全的 components/empty_state.rs::EmptyState
- 删除 api/posts/mod.rs 末尾的 render_markdown_enhanced / slug 工具
re-export:调用方均使用完整路径 crate::api::{markdown,slug}::*,
这两个跨模块短路径无引用
- 删除 api/comments/mod.rs 的 render_comment_markdown re-export:
调用方用完整路径 crate::api::comments::markdown::render_comment_markdown
保留 auth.rs::invalidate_user_sessions:有完整文档说明的预留基础设施
(角色变更/封禁场景),非遗留垃圾。
|
2026-07-14 14:27:31 +08:00 |
|