与Obsidian同步的博客搭建(二)——内容编译与发布边界
当前后端不是一个持续渲染页面的 Web 框架,而是运行在 Node.js 22 上的 TypeScript 内容编译器。它的职责不是“尽量把 Markdown 变成 HTML”,而是先回答:这份内容是否被明确授权公开?
双重白名单
| Vault 根目录 | type |
公开路由 |
|---|---|---|
10 Blog |
blog |
/blog/<slug> |
20 Wiki |
wiki |
/wiki/<slug> |
30 Projects |
project |
/projects/<slug> |
50 Daily |
daily |
/daily/<slug> |
60 Temp |
temp |
/temp/<opaque-slug> |
路径和类型必须同时匹配。Tasks、Inbox、Private、Archive 和 System 不进入候选集合;缺少 publish: true 或正整数 publish_revision 的文件也不会生成页面。
Published Revision
普通编辑不会直接改变网站。第一次发布把修订号从 0 提升到 1;后续只有“更新已发布修订”才会继续加 1。编译器遇到相同修订号时复用上次保留的产物,即使本地草稿已经继续编辑,线上仍保持已明确发布的版本。
这让“正在写”和“已经公开”成为两个不同状态,也避免同步到一半时把半篇文章推上网站。
一致快照与严格校验
构建开始前会两次计算允许输入的清单;两次结果不同说明同步仍在变化,候选构建会被丢弃并重试。稳定后继续检查:
- UUIDv7 身份、类型、slug 和修订号是否合法;
- ID、slug 和公开路由是否重复;
- 本地图片、视频和 wikilink 是否能够解析;
- 链接是否试图从公开文章穿透到私人笔记;
- HTML 是否包含危险标签、事件属性或越权远程资源;
- 临时分享是否过期,并且是否被搜索、订阅和互动代码排除。
任一必需资源缺失都会让候选失败,当前网站保持不动。
Markdown、链接和资源
Markdown 经过结构化解析、HTML 清理和资源收集。只有已发布内容引用到的资源会被复制,并以内容哈希命名;普通外链可以保留,远程媒体只允许经过审查的专用图片域名。内部 wikilink 根据稳定 ID 解析,未公开目标不会泄漏私有标题或路径。
从 Obsidian 发起发布
Bedic Publisher 在桌面端提供发布、更新修订、取消发布和临时分享动作。它先验证当前笔记,再通过编辑器 API 修改前置属性。后台迁移和维护则使用原子 Vault API,避免与同步或其他插件同时写入时互相覆盖。
上一份 Rust 扫描器和文件监听器已经退役:服务器不再把整个 Vault 当作运行时数据库。下一篇继续说明通过编译后的内容怎样变成可回滚的静态 Release。
上一篇:与Obsidian同步的博客搭建(一)——前言
下一篇:与Obsidian同步的博客搭建(三)——不可变Release与交互服务