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:
@@ -21,12 +21,12 @@ use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
DeadLetterService, DocsService, EmailService, FilesService, GroupDocsService,
|
||||
GroupFilesService, GroupKvService, HttpService, InvokeService, KvService, ModuleSource,
|
||||
NoopDeadLetterService, NoopDocsService, NoopEmailService, NoopEventEmitter, NoopFilesService,
|
||||
NoopGroupDocsService, NoopGroupFilesService, NoopGroupKvService, NoopHttpService,
|
||||
NoopInvokeService, NoopKvService, NoopModuleSource, NoopPubsubService, NoopQueueService,
|
||||
NoopSecretsService, NoopUsersService, NoopVarsService, PubsubService, QueueService,
|
||||
SecretsService, ServiceEventEmitter, UsersService, VarsService,
|
||||
GroupFilesService, GroupKvService, GroupPubsubService, HttpService, InvokeService, KvService,
|
||||
ModuleSource, NoopDeadLetterService, NoopDocsService, NoopEmailService, NoopEventEmitter,
|
||||
NoopFilesService, NoopGroupDocsService, NoopGroupFilesService, NoopGroupKvService,
|
||||
NoopGroupPubsubService, NoopHttpService, NoopInvokeService, NoopKvService, NoopModuleSource,
|
||||
NoopPubsubService, NoopQueueService, NoopSecretsService, NoopUsersService, NoopVarsService,
|
||||
PubsubService, QueueService, SecretsService, ServiceEventEmitter, UsersService, VarsService,
|
||||
};
|
||||
|
||||
/// SDK service bundle. See module docs for the lifecycle and the v1.1.x
|
||||
@@ -133,6 +133,12 @@ pub struct Services {
|
||||
/// `files::shared_collection(name)`. Wired via [`Services::with_group_files`];
|
||||
/// defaults to `NoopGroupFilesService`.
|
||||
pub group_files: Arc<dyn GroupFilesService>,
|
||||
|
||||
/// Shared cross-app group TOPICS (§11.6 D2). Scripts get
|
||||
/// `pubsub::shared_topic(name)` — publish to a group-scoped topic watched by
|
||||
/// `shared = true` group pubsub triggers. Wired via
|
||||
/// [`Services::with_group_pubsub`]; defaults to `NoopGroupPubsubService`.
|
||||
pub group_pubsub: Arc<dyn GroupPubsubService>,
|
||||
}
|
||||
|
||||
impl Services {
|
||||
@@ -178,6 +184,7 @@ impl Services {
|
||||
group_kv: Arc::new(NoopGroupKvService),
|
||||
group_docs: Arc::new(NoopGroupDocsService),
|
||||
group_files: Arc::new(NoopGroupFilesService),
|
||||
group_pubsub: Arc::new(NoopGroupPubsubService),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +210,13 @@ impl Services {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the §11.6 D2 shared group-TOPIC service (picloud binary; tests leave noop).
|
||||
#[must_use]
|
||||
pub fn with_group_pubsub(mut self, group_pubsub: Arc<dyn GroupPubsubService>) -> Self {
|
||||
self.group_pubsub = group_pubsub;
|
||||
self
|
||||
}
|
||||
|
||||
/// All-noop bundle for tests that build an `Engine` but don't
|
||||
/// exercise the stateful services. Returns the same shape as
|
||||
/// `Services::new` so callers can't accidentally rely on a stub
|
||||
|
||||
Reference in New Issue
Block a user