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,10 +5,13 @@ import (
|
||||
|
||||
"connectrpc.com/connect"
|
||||
"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/crypto"
|
||||
"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/subscriptions"
|
||||
)
|
||||
|
||||
// ServiceDeps provides dependencies that plugins need for RPC service handlers.
|
||||
@ -18,6 +21,9 @@ type ServiceDeps struct {
|
||||
Settings settings.Settings
|
||||
Gating gating.Gating
|
||||
Crypto crypto.Crypto
|
||||
Menus menus.Menus
|
||||
PublicUsers auth.PublicUsers
|
||||
Subscriptions subscriptions.Subscriptions
|
||||
|
||||
// Database — for plugin's own sqlc queries
|
||||
Pool Pool
|
||||
@ -36,6 +42,9 @@ type ServiceDeps struct {
|
||||
// Email
|
||||
EmailSender EmailSender
|
||||
|
||||
// Plugin interop
|
||||
Bridge PluginBridge
|
||||
|
||||
// Extension points — typed as narrow interfaces where possible
|
||||
JobRunner JobRunner
|
||||
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