feat(shared-topics): GroupPubsubService + shared publish fan-out + SDK handle (D2)
The runtime for shared topics:
- pubsub_repo: fan_out_publish gains `AND t.shared = FALSE` (a shared
trigger never fires on a per-app publish); new fan_out_shared_publish
matches `shared = true` pubsub triggers on the resolved owning group,
each delivery stamped with the writer app_id (M2 model).
- GroupPubsubService trait (shared) + GroupPubsubServiceImpl: resolve the
owning group (kind='topic') from cx.app_id's chain, require editor+
(GroupPubsubPublish, fails closed for anon), size-cap, fan out.
- SDK: `pubsub::shared_topic("name")` -> GroupTopicHandle with
`.publish(subtopic, msg)` / `.publish(msg)`; wired through Services +
the picloud binary (reuses the one PubsubRepo).
- authz: Capability::GroupPubsubPublish(GroupId), editor+ / script:write.
The owning-group chain walk is the isolation boundary; a sibling-subtree
app never resolves the topic.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -386,6 +386,17 @@ mod tests {
|
||||
self.written.lock().unwrap().extend(staged);
|
||||
Ok(u32::try_from(n).unwrap_or(u32::MAX))
|
||||
}
|
||||
|
||||
async fn fan_out_shared_publish(
|
||||
&self,
|
||||
_ctx: PublishCtx,
|
||||
_owning_group: picloud_shared::GroupId,
|
||||
_topic: &str,
|
||||
_event_payload: serde_json::Value,
|
||||
) -> Result<u32, PubsubRepoError> {
|
||||
// The per-app PubsubService tests don't exercise the shared path.
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
||||
Reference in New Issue
Block a user