feat(content)!: PublishedBlockConfigs capability — published block content crosses the ABI

Adds content.published_block_configs: the host returns the stored
content JSON of every block with a given key inside currently
published page snapshots. Restores server-authoritative per-block
enforcement for sandboxed guests (calcomblock's captcha requirement
was inert under wasm — blockConfig hardcoded nil because no capability
exposed published block content). Breaking: content.Content gains a
method; the cms adapter implements it in the paired bump.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Alex Dunmow 2026-07-07 23:36:17 +08:00
parent 9a4394a07c
commit b5a288c3de
4 changed files with 689 additions and 557 deletions

View File

@ -82,6 +82,18 @@ message PageInfo {
string title = 3;
}
// ContentPublishedBlockConfigsRequest asks the host for the stored content
// (config JSON) of every block with the given key inside a CURRENTLY
// published page snapshot. Lets a guest resolve server-authoritative
// per-block settings (e.g. a captcha requirement) it cannot query itself.
message ContentPublishedBlockConfigsRequest {
string block_key = 1;
}
message ContentPublishedBlockConfigsResponse {
repeated bytes configs = 1; // each entry: one block's content as JSON
}
message ContentGetPostRequest {
string slug = 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -59,6 +59,12 @@ type ListPostsParams struct {
type Content interface {
GetAuthorProfile(ctx context.Context, id uuid.UUID) (*AuthorProfile, error)
GetPage(ctx context.Context, slug string) (*PageInfo, error)
// PublishedBlockConfigs returns the stored content (config) of every block
// with the given key inside a currently published page snapshot. This is
// the server-authoritative source for per-block settings a sandboxed guest
// cannot query itself (e.g. whether any published booking block demands
// captcha) — never trust the same flags from the client request.
PublishedBlockConfigs(ctx context.Context, blockKey string) ([]map[string]any, error)
GetPost(ctx context.Context, slug string) (*PostInfo, error)
ListPosts(ctx context.Context, params ListPostsParams) ([]PostInfo, error)
Slugify(text string) string

View File

@ -47,6 +47,22 @@ func (s *contentStub) GetPage(ctx context.Context, slug string) (*content.PageIn
return &content.PageInfo{ID: parseUUID(p.GetId()), Slug: p.GetSlug(), Title: p.GetTitle()}, nil
}
func (s *contentStub) PublishedBlockConfigs(ctx context.Context, blockKey string) ([]map[string]any, error) {
resp := &abiv1.ContentPublishedBlockConfigsResponse{}
if err := s.invoke(ctx, "published_block_configs", &abiv1.ContentPublishedBlockConfigsRequest{BlockKey: blockKey}, resp); err != nil {
return nil, err
}
configs := make([]map[string]any, 0, len(resp.GetConfigs()))
for _, raw := range resp.GetConfigs() {
var m map[string]any
if err := json.Unmarshal(raw, &m); err != nil {
continue
}
configs = append(configs, m)
}
return configs, nil
}
func (s *contentStub) GetPost(ctx context.Context, slug string) (*content.PostInfo, error) {
resp := &abiv1.ContentGetPostResponse{}
if err := s.invoke(ctx, "get_post", &abiv1.ContentGetPostRequest{Slug: slug}, resp); err != nil {