|
|
6fee07df1f
|
feat(markdown): 文章页脚注完整支持(语义化 + back-link + 样式)
切换到 pulldown-cmark 的 GFM 脚注模式(与 GitHub 行为一致),并用自定义
事件渲染器替换默认输出,补齐语义化结构与无障碍属性:
- 解析:Options::all() 同时置 ENABLE_OLD_FOOTNOTES(bit 9|2),使
has_gfm_footnotes() 返回 false 走 OLD 模式。remove(OLD) 会连
ENABLE_FOOTNOTES 一起清掉(OLD 位掩码含 bit 2),故 remove 后须
insert(ENABLE_FOOTNOTES) 单独加回。
- 渲染:事件循环新增 FootnoteReference / Start/End FootnoteDefinition
三个分支。引用处 <sup class="fn-ref" id="fnref:{label}-{n}"> 带
role="doc-noteref";定义处 <aside role="doc-footnote"
aria-labelledby="..."> 取代默认 <div>;End 处按引用次数输出 N 个
back-link(↩、↩²、↩³…)指向各自引用位置,role="doc-backlink"。
- 编号:按 label 首次出现顺序分配(1,2,3…),与定义位置无关。第一遍
遍历顺带统计(复用现有两遍遍历模式,零额外扫描成本)。
- id 安全:footnote_id() 保留 label 原文(不转拼音),仅把 ASCII 标点
/空格转 -,确保 ref↔def 双向一致且不破坏 HTML 属性。
sanitizer:放行 <section> 与 aria-labelledby;修复 is_safe_url 对
含冒号锚点(如 #fn:label)的误判——fragment 内冒号不是 scheme 分隔符,
# 开头的 URL 优先按锚点放行。
input.css:仿 blockquote 视觉语言(左侧边框 + 次级文本色)补脚注样式,
复用 paper 色彩变量,暗色模式自动适配。
|
2026-07-17 10:57:40 +08:00 |
|
|
|
3831d1af01
|
feat(header): 搜索入口改为图标按钮
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
将前台 Header 文本导航中的「搜索」项移除,改在 Header 右侧(主题切换按钮
左边)以放大镜图标 Link 呈现。样式与 ThemeToggle 对齐(圆形 padding、
currentColor 图标),适配明暗主题。
- nav.rs: 导航项列表去掉 Search,更新文档注释
- header.rs: 新增 SearchIconLink 组件(SVG 内联,fill=currentColor)
- frontend_layout.rs: right_content 在 ThemeToggle 前插入 SearchIconLink
|
2026-07-17 10:28:39 +08:00 |
|
|
|
fac247f60a
|
feat(mermaid): 流程图配色对齐 Catppuccin + 容器美化
mermaid.initialize 之前用内置 'default'/'dark' 主题,配色与站点 Catppuccin
调色板完全脱节,图是"外来"的样子;且零 mermaid 专用 CSS,SVG 直接套在通用
pre 容器里,宽图横向滚动、无居中无留白。
改动:
- mermaid.ts:theme 切到 'base'(base 不硬编码颜色,themeVariables 能完全
控制调色板;'default' 主题硬编码 mainBkg=#ECECFF 会阻断覆盖)。新增 Latte/
Mocha 两套 themeVariables,节点用 surface 色阶、边框/连线用 subtext 色阶、
文字用 primary text,hex 取自 themes/*.tmTheme。flowchart 配 basis 平滑曲线
+ diagramPadding 16 + useMaxWidth:true(配合 CSS 消除横向滚动)。
- input.css:新增 .md-content pre[data-mermaid-rendered] 规则,flex 居中 + svg
max-width:100% 缩放适配;.mermaid-error 加 accent 色左边条提示。
- mermaid.test.ts:theme 断言同步到 'base'+darkMode;新增 themeVariables
注入测试(钉住 Latte/Mocha 关键 hex)。
范围:纯前端 TS + CSS,零 Rust 改动。
|
2026-07-17 10:13:20 +08:00 |
|
|
|
302e05fe1f
|
fix(docker): 补齐 Dockerfile 缺失的 katex-css 与 restore-webp 步骤
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
对齐 make build-linux 流水线,修两个同步遗漏:
- katex-css:镜像缺此步导致 $...$/$$...$$ 渲染成裸 span,无 KaTeX
字体排版。
- restore-webp:dx 0.7.9 会把 public/*.webp 重编码成 VP8L 静图(动画帧
丢失、体积反增 7-8×),需用源文件覆盖回 dx 产物目录后再拷贝。
两处均在注释中标注 keep in sync with make build-linux。
|
2026-07-16 18:16:35 +08:00 |
|
|
|
71211bc68d
|
chore(docker): GitHub Releases 下载走 gh-proxy 镜像
dx tarball 与 tailwindcss 二进制都在 github.com releases 上,国内下载
~300KB/s 且频繁连接重置。新增 ARG GH_PROXY (默认 https://gh-proxy.com)
前缀到两处 GitHub 下载 URL;传空值可回退直连,便于非大陆环境构建。
|
2026-07-16 18:03:09 +08:00 |
|
|
|
ae1efda462
|
fix(build): build 前清除 static/ SSR 缓存目录
避免增量构建时残留的 SSR 缓存导致页面内容不更新。
与 make clean 中已有的 static/ 清理保持一致。
|
2026-07-16 17:39:44 +08:00 |
|
|
|
aac0c8198d
|
fix(docker): 升级 builder 至 trixie 以满足 dx 对 GLIBC_2.39 的需求
dx v0.7.9 预编译二进制(both aarch64/x86_64-unknown-linux-gnu)依赖
GLIBC_2.39,而 Debian Bookworm (glibc 2.36) 不满足该要求。
将 builder 阶段基础镜像从 rust:1.96-bookworm 升级至
rust:1.96-trixie (Debian 13, glibc 2.41)。
|
2026-07-16 17:39:41 +08:00 |
|
|
|
0395c55213
|
fix(mermaid): 修复 tsc 类型错误
- mermaid.ts: initMermaid 早退路径(root 未命中)返回 Promise.resolve() 而非
undefined,匹配 Promise<void> 签名。
- theme-transition.test.ts: resolveAsync 改用 mutable 容器 { fn: null } 包裹,
绕过 TS 跨闭包控制流收窄(原 let + 闭包赋值,在 ?.() 处被判定为 null → never)。
上提交漏跑 tsc --noEmit(vitest 用 esbuild 不做类型检查),本次补验 tsc + vite build。
|
2026-07-16 17:06:06 +08:00 |
|
|
|
bdfc7a19e9
|
feat(mermaid): 流程图主题切换跟随 VT 圆形扩散动画
此前 mermaid.render() 异步,而 VT 回调同步,Dioxus effect 重跑发生在 VT 回调
之后的微任务,导致动画期间流程图不变、动画结束后才瞬切。
利用 startViewTransition 回调可返回 Promise 的特性(浏览器等其 resolve 才拍
NEW 快照、播动画),让 VT 回调等 mermaid 重渲染完成,新主题流程图进入快照,
圆形扩散覆盖整页含 mermaid 区域。
改动:
- theme-transition.ts: 新增 onThemeChange registry(回调可返回 Promise)。
notifyThemeChange 遍历 registry 收集 Promise 返回聚合结果;THEME_CHANGE_EVENT
事件保留(给 codemirror/xterm 同步换肤,向后兼容)。
startThemeTransition 的 VT 回调改为 async,await notifyThemeChange 聚合 Promise,
确保异步换肤组件(mermaid)完成后再拍 NEW 快照。
applyResolvedTheme(跟随系统瞬切)不等 registry,保持瞬切语义。
- mermaid.ts: 顶层注册 onThemeChange 订阅,listener 调 rerenderExistingBlocks 并
返回其 Promise,供 VT 回调等待。initMermaid/rerenderExistingBlocks 返回 Promise。
- post_content.rs: VT 期间(is-theme-transitioning)跳过 __initMermaid 调用,避免
Dioxus effect 抢先重渲染穿透伪元素快照(照搬 code_runner/runner.rs 守卫);
动画结束后 effect 重跑做幂等兜底。
- theme-transition.test.ts: VT callback 签名 void→Promise<void>,新增 registry
等待测试 + 降级路径不等 registry 测试。
|
2026-07-16 16:58:27 +08:00 |
|
|
|
6eb7a743e5
|
fix(mermaid): 主题切换时重渲染已渲染的流程图
mermaid 把颜色烤进 SVG 内联样式,无法靠 CSS 原地切主题。此前 initMermaid
的幂等守卫一刀切跳过所有已渲染块,导致切主题后流程图停留在首次渲染的主题。
改动:
- initMermaid 改为双路径分发:未渲染块(<code>还在)走 IntersectionObserver
懒加载;已渲染块(pre 内容已是 SVG)按 dataset.mermaidSource 缓存源码重渲染,
同主题幂等跳过,主题变化才重渲染。
- 渲染逻辑抽到 renderBlock:用全局自增 renderCounter 生成唯一 id,避开 mermaid
残留的 d-前缀布局节点冲突(#357)与同页 marker id 冲突(#5741);替换前清空
pre.innerHTML 确保亮/暗两版 SVG 不并存。
- source 存进 dataset.mermaidSource 供重渲染回取(此时 <code> 已被 SVG 替换)。
触发机制不变:post_content.rs 的 use_effect 读 use_resolved_theme() 建订阅,
主题切换时重跑重调 __initMermaid 传入新 theme;mermaid.ts 据此决定是否重渲染。
|
2026-07-16 16:42:04 +08:00 |
|
|
|
f7a3336b76
|
style(details): 正文折叠块卡片化,自绘 chevron + hover/focus 态
正文手写的 <details>(区别于 .toc 导航块)此前只有浏览器默认样式
(灰三角 + 裸文字),与文章 Catppuccin 设计语言断档。
复用代码块/blockquote 的视觉语言:同款底色 + 边框 + 16px 圆角;
自绘 chevron 替代原生三角,展开旋转 90° 平滑过渡;
补 hover 浅背景与 :focus-visible 轮廓(WCAG 2.4.7);展开内容补
左右内边距与首尾 margin。
作用域 .md-content details:not(.toc),与 TOC 专用样式互不干扰。
|
2026-07-16 16:31:00 +08:00 |
|
|
|
45122fc687
|
fix(post): scrollToHash 增加一次性守卫,切主题不再跳回 URL hash
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
PostContent 的 use_effect 读取 resolved_theme() 建立订阅,主题切换时重跑
(为重跑 mermaid 主题)。但该 effect 同时调用 __scrollToHash,主题切换会
把页面跳回 URL hash 位置——即使该 hash 早已不在用户视野。
scrollToHash 是首屏异步取数后的补救滚动(弥补骨架屏阶段标题 DOM 缺失导致的
原生 fragment-scroll 失效),本质上是一次性的,不应随主题切换重跑。增加
did_scroll 信号守卫,仅首次 effect 运行时调用。
|
2026-07-16 16:22:42 +08:00 |
|
|
|
f6b7ab4333
|
fix(post): scrollToHash 增加 ResizeObserver 布局稳定期,修正 mermaid 异步渲染导致的锚点落点偏移
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
直接访问 /post/slug#heading 或刷新该 URL 时,目标标题停在屏幕中间偏下,但点击目录
或标题跳转却正常。根因是时序竞争:
post_content 的 use_effect 同步依次调用 __initMermaid(注册 IntersectionObserver,
异步)→ __scrollToHash。scrollToHash 的"立即 + 两帧"校正只覆盖浏览器原生
fragment-scroll;而 mermaid 懒加载(加载 ~1MB bundle → render → pre.innerHTML=svg)
是数百毫秒的异步链,发生在两帧之后。mermaid 块从源码文本膨胀成 SVG 图时撑高内容,
把目标标题推离已校准的落点。mermaid.ts 渲染完成后无任何落点修正。点击目录正常是
因为那时 mermaid 已渲染、布局稳定。
解法:scrollToHash 末尾新增 stabilizeScrollOnResize——在 STABILIZE_WINDOW_MS(2s) 内
用 ResizeObserver 观察 .post-content 容器,检测到布局变化即用 rAF 合并重新校正一次
落点。与 mermaid 解耦,同时覆盖图片/字体等所有异步位移源。用户主动滚动(wheel/
touchmove/keydown)或超时后自动停止,不与交互打架。重入安全:主题切换重跑 use_effect
时先 dispose 上一次稳定器,避免泄漏/叠加。
测试(hash-scroll.test.ts)新增 3 例:resize 后再校正、用户 wheel 后停止、重入清理旧 RO。
|
2026-07-16 16:05:11 +08:00 |
|
|
|
1ea11b6434
|
style(checkbox): 文章页 task-list checkbox 改用 appearance:none 自绘圆角方框
原生 checkbox 形状随浏览器而异(Safari 圆角小框/Chrome 直角),
accent-color 只能上色无法统一形状。改为全自定义:
- appearance:none + 4px 圆角 + 1.15rem 方框
- 勾选时 accent 绿填充,对勾用内联 SVG background
(<input> 是替换元素,吃不到伪元素)
- 亮色:中绿底 #40a02b + 白对勾(对比 ≥4.5:1)
- 暗色:浅绿底 #a6e3a1 + 深对勾 #1e1e2e(白对勾在浅绿上对比不足)
- 文章内 checkbox 是 disabled 展示态,故不加 focus/cursor 交互
|
2026-07-16 15:58:54 +08:00 |
|
|
|
e526da0571
|
style(code-block): 代码块字号从 13.6px 调整为 16px
.md-content pre code 的 font-size 由 0.85em 改为 1rem,
锚定根字号 16px 以提升代码块可读性。行间 code 保持 0.85em 不变。
|
2026-07-16 15:52:58 +08:00 |
|
|
|
445b92f407
|
fix(mermaid): 改用 script 标签加载 IIFE bundle,修正全局变量取值
根因:mermaid bundle 是 IIFE 格式(与项目其他前端库一致),挂全局变量
而非 ES module export。但 mermaid.ts 错用了 import() 取 .default——
IIFE 无 export,mod.default 是 undefined,导致 mermaid.initialize 调用
TypeError,流程图永远不渲染(数学公式不受影响,因为是服务端渲染)。
修复:
- mermaid.ts: loadMermaidBundle 改用动态注入 <script src=/mermaid/mermaid.js>
标签,加载后从 window.MermaidRenderer 取(与 codemirror/lightbox 的
Reflect::get(window,...) 模式一致)
- mermaid-renderer/index.ts: 显式 globalThis.MermaidRenderer = mermaid,
避免 vite IIFE 把 export default 编译成 .default 多一层
- markdown.rs: mermaid 代码块跳过 syntect 高亮(无语法定义且会包 <span>
污染 textContent),直接输出转义纯源码
前端 28 测试 + Rust 557 测试 + 双 target 编译通过。
|
2026-07-16 15:36:07 +08:00 |
|
|
|
ac04b23b59
|
chore(build): make clean 清除 static/ SSR 缓存目录
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
|
2026-07-16 15:15:55 +08:00 |
|
|
|
f613460742
|
fix(docker): 修复 DX 下载 case 分支行延续导致的解析失败
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
Dockerfile 的 RUN 指令只在行尾有反斜杠时延续到下一行。
DX 下载步骤的 amd64/arm64 分支把 DX_TRIPLET 和 DX_SHA256 拆成两行,
首行缺少续行符,Docker 把次行 DX_SHA256=... 当成新的顶层指令,
报错 unknown instruction: DX_SHA256=...。
改成与同文件其它 case 块(Node/Tailwind/musl)一致的写法:
每个分支单行、以 ;; 收尾。SHA256 值已对照 GitHub 官方 .sha256 旁挂文件核对一致。
|
2026-07-16 15:15:12 +08:00 |
|
|
|
438a5e1046
|
fix(ssr): 文章写入后物理删除 SSR 磁盘缓存,根治'重建后内容不更新'
Dioxus 0.7 增量渲染器把每路由 SSR 结果落盘到 static/<route>/index/<hash>.html,
只暴露 invalidate_after(ttl) 一个失效手段,无按路由失效的公开 API。
之前 bump_global_generation 在 Dioxus 0.7 不生效(ssr_cache.rs 注释已承认),
导致文章重建/编辑后,即便 DB content_html 已是新内容,SSR 缓存仍返回旧页面,
最长滞后 SSR_CACHE_SECS(默认 3600s)。本次 katex/mermaid 渲染不生效即因此。
修复:在 ssr_cache.rs 新增物理删除缓存的函数:
- invalidate_ssr_route(route): 删 static/<route>/ (含路径穿越防护)
- invalidate_ssr_all_public(): 删 static/ 下除 .well-known/admin 外全部
- invalidate_ssr_home(): 删 static/index/ (细粒度,allow dead_code)
所有写路径(create/update/rebuild/delete/trash)在事务提交后调用:
- 单篇操作失效 /post/{slug} + 全量公开页(列表项变化影响首页/归档/标签)
- 批量操作直接全量失效
世代号保留作 X-SSR-Generation 可观测性,实际失效靠删文件。
顺带修 katex.rs 的 clippy(field_reassign_with_default)+ cmp_owned。
556 Rust 测试 + clippy -D warnings + 双 target 编译通过。
|
2026-07-16 15:11:34 +08:00 |
|
|
|
09ca480842
|
chore(docker): 移除 gh-proxy,改用 GitHub 直连下载 dx 与 Tailwind
Dioxus CLI 与 Tailwind CSS 独立二进制此前经 gh-proxy.com 镜像下载,
现移除 GH_PROXY 前缀及相关注释,直接从 GitHub Releases 拉取。
|
2026-07-16 14:51:21 +08:00 |
|
|
|
78a8d188d1
|
fix(admin): 重建结果消息改绝对定位,避免撑高容器顶起按钮
RebuildCacheBar 原用 flex-col 把「已重建 x 篇文章」消息排在按钮下方,
参与文档流。其祖先 header 为 md:items-end(底边固定),消息出现时
新增高度全部转化为按钮上移,「重建内容/重建全部」被顶起、「发布文章」
相对下沉,三者错位。
改为外层 relative + 消息 absolute top-full 脱离文档流:出现/消失都
不影响按钮行高度,布局稳定。双 target 编译通过。
|
2026-07-16 14:36:33 +08:00 |
|
|
|
f39cb35a31
|
docs: 补充数学公式与流程图架构说明
AGENTS.md 新增 'Math & Diagrams' 章节详述两条渲染路径:
- KaTeX 服务端渲染:katex-rs + pulldown-cmark ENABLE_MATH + sanitizer span
白名单 + 自托管 CSS/字体(make katex-css)
- mermaid 客户端懒加载:IntersectionObserver + 动态 import 独立 bundle
同步更新:Server-only deps 加 katex-rs、Frontend Lib 表加 mermaid-renderer 行、
Build Artifacts 加 public/{katex,mermaid}、markdown.rs 描述。
|
2026-07-16 14:24:38 +08:00 |
|
|
|
70edc5e46c
|
feat(frontend): mermaid 流程图懒加载渲染
mermaid 无官方 SSR 支持,采用客户端 IntersectionObserver 懒加载:服务端
markdown.rs 只产出普通 <pre><code class="language-mermaid"> 代码块,
前端在块进视口时动态 import 独立 bundle(~1MB)渲染成 SVG。
新增 libs/mermaid-renderer/:mermaid 11.16 IIFE bundle,输出 public/mermaid/
yggdrasil-core/mermaid.ts:扫描 language-mermaid 块,视口可见时动态 import
/mermaid/mermaid.js(单例缓存),mermaid.initialize 适配 light/dark 主题,
securityLevel=strict;渲染失败加 .mermaid-error class 保留源码;幂等守卫
post-content.ts:initCopyButtons 跳过 language-mermaid 块(图无需 copy)
post_content.rs:use_effect 调 __initMermaid('.post-content', theme),
读 use_resolved_theme() 传主题并建立订阅
新增 6 个 mermaid 单测(扫描/主题/幂等/非mermaid/未命中/错误回退)。
550 Rust + 28 前端测试全过,双 target 编译通过。
|
2026-07-16 14:22:43 +08:00 |
|
|
|
218533402b
|
feat(css): 自托管 KaTeX CSS 与 woff2 字体
服务端 katex-rs 只输出 HTML span,字体/排版靠配套 CSS。从 npm 包 katex
0.16.x 的 dist/ 拷贝 katex.min.css + woff2 字体(省去 woff/ttf)到 public/katex/,
CSS 用相对 url(fonts/) 引用故两者须同级。
- libs/package.json: katex ^0.16.22 作 workspace 根 devDependency
- Makefile: 新增 katex-css target,接入 build/build-linux/dev;clean 清 public/katex
- Dioxus.toml: [web.resource]/[web.resource.dev] style 列表注册 /katex/katex.min.css
- .gitignore: public/katex 作构建产物忽略(同 highlight.css 等)
make katex-css 验证通过:23KB CSS + 20 个 woff2 字体就位。
|
2026-07-16 14:15:20 +08:00 |
|
|
|
84f6223c68
|
feat(markdown): 评论支持数学公式渲染
- comments/markdown.rs: 开启 ENABLE_MATH,InlineMath/DisplayMath 事件
渲染成 katex HTML 注入事件流(评论不用块级 <p> 包裹,保持紧凑)
- sanitizer.rs: 评论路径 span 白名单加 style(KaTeX 内联定位 style 需保留,
与文章正文 sanitizer.rs:382 对齐)
- 新增 3 个评论公式测试(内联/块级/style 保留)
双 target 编译通过,24 个评论测试 + 36 个 sanitizer 测试全过。
|
2026-07-16 14:12:20 +08:00 |
|
|
|
95fe9d862d
|
feat(markdown): 文章支持数学公式 SSR 渲染
render_markdown_enhanced 事件循环新增 InlineMath/DisplayMath 分支:
- $...$ 内联公式调 katex::render_inline 注入 span
- $$...$$ 块级公式用 <p class="math-display"> 包裹 katex 输出
- 标题内公式按内联渲染,不产生块级 <p>
pulldown-cmark 的 Options::all() 已含 ENABLE_MATH,无需改 options。
新增 5 个端到端测试(内联/块级/标题内/坏公式不破坏全文)。
双 target 编译通过,16 个 markdown 测试全过。
|
2026-07-16 14:11:05 +08:00 |
|
|
|
891a576dc0
|
feat(deps): 引入 katex-rs 服务端数学公式渲染
纯 Rust 的 katex-rs 0.2.4 重实现 KaTeX,把 TeX 公式渲染成 HTML span,
供后续 pulldown-cmark 的 InlineMath/DisplayMath 事件调用。
- Cargo.toml: katex-rs 作为 optional dep 经 server feature 启用
- src/api/katex.rs: thread_local 缓存 KatexContext/Settings(因含 RefCell
宏表非 Sync,不能放全局 static);OutputFormat::Html 避开 MathML 标签
使 sanitizer 无需开白名单;throw_on_error=false 防坏公式中断全文
- src/api/mod.rs: #[cfg(feature="server")] 注册 katex 模块
双 target 编译通过(server + wasm32),4 个单测通过。
|
2026-07-16 14:09:14 +08:00 |
|
|
|
1935321da1
|
build(deps): 升级 TypeScript 至 7.0.2(Go 原生编译器)
CI / check (push) Has been cancelled
CI / build (push) Has been cancelled
TypeScript 7 已将 Go 重写版(代号 Corsa)合并进主线 typescript 包,
npm latest 即 7.0.2,无需再依赖 @typescript/native-preview 预览包。
本项目单点改动:libs/package.json devDependencies.typescript ^6.0.3 -> ^7.0.2
(6 个子包均从 workspace 根继承版本,无需逐包改动)。
兼容性核对(TS 7 破坏性变更 vs tsconfig.base.json):
- target ES2020 / module ESNext / moduleResolution bundler 均在支持范围
- 未使用 baseUrl / node10 / es5 等 TS 7 移除的选项
- esModuleInterop=true / strict=true 满足 TS 7 的新下限要求
- css 副作用导入已有 css.d.ts 声明,满足 noUncheckedSideEffectImports 新默认值
验证:typecheck(6 包 tsc --noEmit) + build(6 包 tsc && vite build)
+ test(187 个 vitest 用例)全部通过。
|
2026-07-16 13:36:54 +08:00 |
|
|
|
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 |
|