fix(metadata,client): subscribeMetadata 交付真正的 MetadataEvent——生产者履约 + 边界校验 (#4602) - #4628
Merged
Merged
Conversation
…— producer fulfils the declared contract (#4602) MetadataManager now builds a schema-valid MetadataEvent (generated uuid id, flattened top-level metadataType/name/definition, userId when the write declares an actor via the new MetadataWriteOptions.userId seam), validates it with MetadataEventSchema.parse before publishing, and carries it as the RealtimeEventPayload envelope's payload. A register() overwrite now publishes metadata.{type}.updated (mirroring the added/changed watcher split) instead of a second .created. Types outside the closed MetadataEventType enum publish nothing (declared = enforced) instead of an event every compliant consumer must reject. The client SDK's subscribeMetadata unwraps the envelope and validates with MetadataEventSchema.safeParse at the boundary — off-contract payloads are rejected loudly (callback never invoked), and the 'as any as MetadataEvent' double-cast is deleted. client-react's metadata hooks delegate to it and are fixed transitively. Out-of-scope findings filed: #4626 (subscribeData/DataEvent twin defect), #4627 (MetadataEventType enum coverage vs registrable types). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 112 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
August 2, 2026 12:10
os-zhuang
enabled auto-merge
August 2, 2026 12:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4602
按 PM 裁决(方案 1,生产者履约)实施:
MetadataEvent(@objectstack/spec/api)是 #4587 收敛后 realtime 元数据变更的唯一已声明合同,本 PR 让生产侧发布真正的MetadataEvent,消费侧在边界处校验而不是硬铸。生产侧(
packages/metadata)MetadataManager.register()/unregister()构造完整的MetadataEvent:生成 uuidid,metadataType/name/definition顶层铺开,写路径声明了操作者时携带userId,发布前用MetadataEventSchema.parse校验(malformed 在生产端响亮失败,不再把谎话送下游)。RealtimeEventPayload的payload承载完整MetadataEvent。仓内对metadata.{type}.*信封 payload 的唯一读者是 client SDK(webhook auto-enqueuer 只消费data.record.*),因此无信封依赖被破坏——未发现需要 needs_decision 的反证。metadata.{type}.updated(与既有added/changedwatcher 分叉一致),此前.updated声明而无任何生产者。已 pin 测试。MetadataEventType是封闭枚举:枚举外的类型(如translation)没有已声明的 realtime 事件合同,不发布(debug 日志)——发布一个每个合规消费者都必须拒绝的事件更糟(declared = enforced)。覆盖面是否扩枚举/收窄subscribeMetadata参数类型,已立案 MetadataEventType 是 13 类型的封闭枚举,但可注册的 metadata 类型远多于此——枚举外类型的 realtime 事件合同缺位,需裁决覆盖面 #4627 待裁决。消费侧(
packages/client,client-react传递生效)callback(event as any as MetadataEvent)双铸;subscribeMetadata在边界拆信封并MetadataEventSchema.safeParse,不合合同的 payload 响亮拒绝(handler 抛错、回调不触发),绝不静默胁变或透传。client-react的useMetadataSubscription/useMetadataSubscriptionCallback直接委托 client SDK,无自己的铸型,随之修复,无需改动。合同 seam(
packages/spec)MetadataWriteOptions新增可选userId(操作者),让知道 actor 的写路径能把userId带进事件——否则MetadataEvent.userId永远是"声明了但没人能生产"。加法变更,现有调用方不受影响。spec 八项生成产物门禁全绿(check:generated全过,无需重新生成)。测试
packages/metadata/src/metadata-realtime-events.test.ts(9 例):信封 payload 用 spec schema 本体 parse(双方漂移即红);覆盖 created/updated/deleted、userId 携带/缺省、枚举外类型零发布、非 string packageId 剔除、id 唯一、publish 失败不影响写入。packages/client/src/realtime-api.test.ts(5 例):订阅者收到顶层字段(pre-fix 树上必红——旧代码回调收到的是信封,event.name为undefined);pre-fix 生产者形状与错误字段类型均被响亮拒绝且回调不触发;packageId 过滤与退订不回归。@objectstack/metadatatest:14 files / 290 tests 全绿;@objectstack/clienttest:16 files / 209 tests 全绿;spec/client/client-reacttypecheck全绿。范围外发现(已立案,unassigned)
subscribeData/DataEvent同构缺陷(生产者是 ObjectQL engine 热路径,且 webhook auto-enqueuer 直读信封 payload,迁移成本更高,需单独评审)。MetadataEventType枚举只覆盖 13 类型 vs 可注册类型全集,覆盖面需裁决。🤖 Generated with Claude Code
https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5
Generated by Claude Code