package plugin import ( "context" "connectrpc.com/connect" "git.dev.alexdunmow.com/block/pluginsdk/ai" "git.dev.alexdunmow.com/block/pluginsdk/auth" "git.dev.alexdunmow.com/block/pluginsdk/content" "git.dev.alexdunmow.com/block/pluginsdk/crypto" "git.dev.alexdunmow.com/block/pluginsdk/datasources" "git.dev.alexdunmow.com/block/pluginsdk/gating" "git.dev.alexdunmow.com/block/pluginsdk/menus" "git.dev.alexdunmow.com/block/pluginsdk/settings" "git.dev.alexdunmow.com/block/pluginsdk/subscriptions" "github.com/google/uuid" ) // CoreServices provides CMS capabilities to plugins. type CoreServices struct { // Capability interfaces — typed access to CMS functionality Content content.Content ContentAuthor content.Author Settings settings.Settings Gating gating.Gating Crypto crypto.Crypto Menus menus.Menus Datasources datasources.Datasources PublicUsers auth.PublicUsers Subscriptions subscriptions.Subscriptions // Database — for plugin's own sqlc queries Pool Pool // RPC interceptors — core-provided Connect handler options Interceptors connect.Option // Site configuration MediaPath string AppURL string // Media library — deposit images through the full upload pipeline Media Media // AI ToolRegistry ai.ToolRegistry AITextCall func(ctx context.Context, taskKey, systemPrompt, userMessage string) (string, error) // Email EmailSender EmailSender // Plugin interop Bridge PluginBridge // Core RPC services — pre-built bindings for CMS-provided services CoreServiceBindings CoreServiceBindings ReviewSubmitter ReviewSubmitter BadgeRefresher BadgeRefresher SettingsUpdater settings.Updater // Extension points — typed as narrow interfaces where possible JobRunner JobRunner EmbeddingService EmbeddingService RAGService RAGService // Provisioner — idempotent ensure/seed operations. In the wasm world this // is a LOAD-TIME capability: call it from the Load hook, not from // Register/RegisterWithProvisioner (DESCRIBE stubs every host function to // fail, so register-time provisioning cannot cross the ABI). Provisioner Provisioner } // MediaDeposit describes an image a plugin deposits into the CMS media library. // The bytes flow through the same pipeline as an admin upload (optimize, WebP, // thumbnails, LQIP, dimensions); responsive variants are generated on demand. type MediaDeposit struct { // ID is the media row's primary key. REQUIRED for Provisioner.EnsureMedia — // it is the deterministic, template-referable key a seeded {% img %} tag // resolves by. Optional for Media.Deposit, where a zero value is generated. ID uuid.UUID // Filename is the original filename, e.g. "hero.jpg". Filename string // Data is the raw image bytes, typically from go:embed. Data []byte // AltText is optional accessibility text. AltText string // Folder optionally groups the media under a named library folder, // created if absent. Folder string // Source is an optional provenance label, e.g. the plugin name. Source string } // MediaResult reports the outcome of a deposit. type MediaResult struct { // ID is the media row's primary key (the supplied ID, or a generated one). ID uuid.UUID // Ref is a ready-to-use reference ("media:") for a block src or a // {% img %} tag. Ref string // Created is false when an existing row with the supplied ID was reused. Created bool } // Media lets a plugin deposit images into the CMS media library at runtime. // Seed-time deposits use Provisioner.EnsureMedia instead — it is idempotent // (skip if the ID exists; on changed bytes it warns rather than overwriting). type Media interface { Deposit(ctx context.Context, deposit MediaDeposit) (MediaResult, error) } // JobRunner submits background jobs for async processing. type JobRunner interface { Submit(ctx context.Context, jobType string, config []byte) error } // EmbeddingService generates and manages text embeddings. type EmbeddingService interface { GenerateEmbedding(ctx context.Context, text string) ([]float32, error) EmbedContent(ctx context.Context, sourceType string, sourceID uuid.UUID, text string) (bool, error) IsAvailable() bool } // ContentFetcher retrieves the title and full text for a content item so the // RAG service can re-index it after changes. Plugins register one per content type. type ContentFetcher func(ctx context.Context, contentID uuid.UUID) (title string, text string, err error) // RAGService provides retrieval-augmented generation for AI agents. type RAGService interface { Query(ctx context.Context, query string, limit int) ([]RAGResult, error) RegisterContentFetcher(contentType string, fetcher ContentFetcher) OnContentChanged(ctx context.Context, contentType string, contentID uuid.UUID) } // RAGResult is a single result from a RAG query. type RAGResult struct { Content string Score float64 Metadata map[string]string } // BadgeRefresher recomputes badges for a data table row. // The CMS handles loading the table schema, aggregating ratings, // evaluating badge rules, and persisting the updated badge list. type BadgeRefresher interface { RefreshBadges(ctx context.Context, tableID, rowID uuid.UUID) error }