feat: add menus, subscriptions, public users, and plugin bridge to SDK
New capability interfaces: - menus.Menus: menu/nav access (GetMenuByName, GetMenuItems) - subscriptions.Subscriptions: tier/plan access (GetUserTierLevel, GetTierBySlug, ListActivePlans) - auth.PublicUsers: public user profiles (GetByUsername, GetByID) - plugin.PluginBridge: inter-plugin service registry with typed GetServiceAs[T] helper All added to ServiceDeps for plugin consumption. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
43deff21f7
commit
917eee13a2
25
auth/public_users.go
Normal file
25
auth/public_users.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PublicUsers provides public/community user profile access for plugins.
|
||||||
|
type PublicUsers interface {
|
||||||
|
GetByUsername(ctx context.Context, username string) (*PublicUserProfile, error)
|
||||||
|
GetByID(ctx context.Context, id uuid.UUID) (*PublicUserProfile, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicUserProfile is a plugin-facing view of a public user.
|
||||||
|
type PublicUserProfile struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
Email string
|
||||||
|
Username string
|
||||||
|
DisplayName string
|
||||||
|
AvatarURL string
|
||||||
|
Bio string
|
||||||
|
EmailVerified bool
|
||||||
|
Role string
|
||||||
|
}
|
||||||
34
menus/menus.go
Normal file
34
menus/menus.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package menus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Menus provides menu and navigation access for plugins.
|
||||||
|
type Menus interface {
|
||||||
|
GetMenuByName(ctx context.Context, name string) (*Menu, error)
|
||||||
|
GetMenuItems(ctx context.Context, menuID uuid.UUID) ([]MenuItem, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menu represents a named navigation menu.
|
||||||
|
type Menu struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// MenuItem represents a single entry in a navigation menu.
|
||||||
|
type MenuItem struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
MenuID uuid.UUID
|
||||||
|
Label string
|
||||||
|
URL string
|
||||||
|
PageSlug string
|
||||||
|
ParentID *uuid.UUID
|
||||||
|
SortOrder int32
|
||||||
|
OpenInNewTab bool
|
||||||
|
CssClass string
|
||||||
|
ItemType string
|
||||||
|
Icon string
|
||||||
|
}
|
||||||
22
plugin/bridge.go
Normal file
22
plugin/bridge.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package plugin
|
||||||
|
|
||||||
|
// PluginBridge allows plugins to share services with each other.
|
||||||
|
// Plugins register named services during startup; other plugins look them up at runtime.
|
||||||
|
type PluginBridge interface {
|
||||||
|
RegisterService(pluginName, serviceName string, service any)
|
||||||
|
GetService(pluginName, serviceName string) any
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServiceAs retrieves a typed service from the bridge.
|
||||||
|
func GetServiceAs[T any](bridge PluginBridge, pluginName, serviceName string) (T, bool) {
|
||||||
|
var zero T
|
||||||
|
if bridge == nil {
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
svc := bridge.GetService(pluginName, serviceName)
|
||||||
|
if svc == nil {
|
||||||
|
return zero, false
|
||||||
|
}
|
||||||
|
typed, ok := svc.(T)
|
||||||
|
return typed, ok
|
||||||
|
}
|
||||||
@ -5,19 +5,25 @@ import (
|
|||||||
|
|
||||||
"connectrpc.com/connect"
|
"connectrpc.com/connect"
|
||||||
"git.dev.alexdunmow.com/block/core/ai"
|
"git.dev.alexdunmow.com/block/core/ai"
|
||||||
|
"git.dev.alexdunmow.com/block/core/auth"
|
||||||
"git.dev.alexdunmow.com/block/core/content"
|
"git.dev.alexdunmow.com/block/core/content"
|
||||||
"git.dev.alexdunmow.com/block/core/crypto"
|
"git.dev.alexdunmow.com/block/core/crypto"
|
||||||
"git.dev.alexdunmow.com/block/core/gating"
|
"git.dev.alexdunmow.com/block/core/gating"
|
||||||
|
"git.dev.alexdunmow.com/block/core/menus"
|
||||||
"git.dev.alexdunmow.com/block/core/settings"
|
"git.dev.alexdunmow.com/block/core/settings"
|
||||||
|
"git.dev.alexdunmow.com/block/core/subscriptions"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServiceDeps provides dependencies that plugins need for RPC service handlers.
|
// ServiceDeps provides dependencies that plugins need for RPC service handlers.
|
||||||
type ServiceDeps struct {
|
type ServiceDeps struct {
|
||||||
// Capability interfaces — typed access to CMS functionality
|
// Capability interfaces — typed access to CMS functionality
|
||||||
Content content.Content
|
Content content.Content
|
||||||
Settings settings.Settings
|
Settings settings.Settings
|
||||||
Gating gating.Gating
|
Gating gating.Gating
|
||||||
Crypto crypto.Crypto
|
Crypto crypto.Crypto
|
||||||
|
Menus menus.Menus
|
||||||
|
PublicUsers auth.PublicUsers
|
||||||
|
Subscriptions subscriptions.Subscriptions
|
||||||
|
|
||||||
// Database — for plugin's own sqlc queries
|
// Database — for plugin's own sqlc queries
|
||||||
Pool Pool
|
Pool Pool
|
||||||
@ -36,6 +42,9 @@ type ServiceDeps struct {
|
|||||||
// Email
|
// Email
|
||||||
EmailSender EmailSender
|
EmailSender EmailSender
|
||||||
|
|
||||||
|
// Plugin interop
|
||||||
|
Bridge PluginBridge
|
||||||
|
|
||||||
// Extension points — typed as narrow interfaces where possible
|
// Extension points — typed as narrow interfaces where possible
|
||||||
JobRunner JobRunner
|
JobRunner JobRunner
|
||||||
EmbeddingService EmbeddingService
|
EmbeddingService EmbeddingService
|
||||||
|
|||||||
44
subscriptions/subscriptions.go
Normal file
44
subscriptions/subscriptions.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package subscriptions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Subscriptions provides subscription tier and billing plan access for plugins.
|
||||||
|
type Subscriptions interface {
|
||||||
|
GetUserTierLevel(ctx context.Context, userID uuid.UUID) (*TierLevel, error)
|
||||||
|
GetTierBySlug(ctx context.Context, slug string) (*Tier, error)
|
||||||
|
ListActivePlans(ctx context.Context, tierID uuid.UUID) ([]Plan, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TierLevel is the resolved tier for a user.
|
||||||
|
type TierLevel struct {
|
||||||
|
Level int
|
||||||
|
Features []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tier is a subscription tier definition.
|
||||||
|
type Tier struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
Name string
|
||||||
|
Slug string
|
||||||
|
Level int
|
||||||
|
Description string
|
||||||
|
Features []byte
|
||||||
|
IsDefault bool
|
||||||
|
Position int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plan is an active billing plan within a tier.
|
||||||
|
type Plan struct {
|
||||||
|
ID uuid.UUID
|
||||||
|
TierID uuid.UUID
|
||||||
|
BillingInterval string
|
||||||
|
Amount int32
|
||||||
|
Currency string
|
||||||
|
IsActive bool
|
||||||
|
CreatedAt time.Time
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user