2026-09-27·by Sijie Wang#standmeet#architecture#design#events

embed-update-hook

embed 更新 hook:语料变了告诉它的 embed

上级:events

状态: 已在 v0.1.76 发布(2026-09-27)—— 设计与落地记录见 StandMeet 仓库的 docs/design/event-bus-outbox-webhooks.md。standmeet.com 那一侧在它自己的仓库里已写好,尚未部署。

embed 的更新 hook 是挂在 embed 上的一个 webhook 端点,范围就是这个 embed 的访问码。范围内的笔记一变,展示它的站点就会知道,并且只重读变了的部分。

想法从哪来

standmeet.com 通过一个 embed 把 owner 的语料展示成博客。它原本无从得知语料变了:盘点里“embed 的消费方(standmeet.com)”一栏的机制是“无”。更新 hook 是事件总线计划的第三期,standmeet.com 是它的第一个消费方。

一个字段,一个挂上的端点

embeds.create 和 embeds.update 接受 update_hook_url;embed 表单里有「更新 hook 地址」字段。填了就创建或更新这个 embed 的端点(这个 upsert 有自己的 UT):

  • event_types = ["corpus.note.changed"]。
  • 设上 embed_id,范围取自 embed 的访问码:角色 glob 减去码的 deny。由 access 域回答(EmbedAdmits),用的就是所有读取都走的 entity.AllowsCorpusEntry。码被吊销或过期、embed 被删,一律不放行。raw:// 永不出。
  • 响应带 update_hook {endpoint_id, url};签名密钥只在端点刚创建时返回。
  • payload 是 thin 的;接收方用 embed 本来就用的授权 API 读正文。embed 怎样在不携带访问码的前提下认证,见 embed-credential-never-carries-the-code。
  • /api/v1/corpus-cards 带 updated_at(精确到秒),接收方据此判断哪些卡片变了。

standmeet.com 收到更新的全过程

  • 博客页、RSS、博客 sitemap 和“最新笔记”都在请求时从 Workers KV 渲染(Astro 的 Cloudflare 适配器)。只有博客路由设 prerender = false;落地页上的“最新笔记”是一个 server island。
  • POST /api/corpus-hook 按 Standard Webhooks 验签,时间戳窗口 ±5 分钟;按 webhook-id 去重(在 KV 里记 24 小时);重新列出卡片,只抓 updated_at 变了的条目,两种语言都抓。
  • 链接在请求时按当前索引解析,重命名或删除不会留下失效链接。
  • KV 为空时,第一个请求从实例把它填满(自举)。没有定时任务。
  • 部署需要 KV namespace id 和 CORPUS_HOOK_SECRET。
  • standmeet.com 这一侧在另一个仓库(atmaxmoj/standmeet-landing)。

不要对账任务

owner 决定不要任何对账循环。送达要么有保证,要么失败看得见:outbox、持久任务、面板告警已经兜住(message-loss-guarantees)。对账是在掩盖不可靠的投递;投递可靠了就不需要。

验收

  • e2e embed-update-hook(已通过):embed 表单填 hook → 改笔记 → sink 收到;cards 带 updated_at;改范围外的笔记不会到达 hook(哨兵式)。
  • 真环境(未完成):在 sijie.xyz 改笔记 → 60 秒内 standmeet.com 页面更新,不部署。部署 standmeet.com 之后验证,归档到 docs/real-env-verification/。见 events-roadmap · events-test-plan。
about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →

embed-update-hook