Documentation
¶
Overview ¶
Package forgesocial provides platform publishing for Forge applications. It supports scheduling and publishing content to Mastodon and LinkedIn via OAuth 2.0.
Quick start ¶
import forgesocial "forge-cms.dev/forge-social"
social := forgesocial.New(db, forgesocial.Config{
Secret: cfg.Secret,
Mastodon: forgesocial.MastodonConfig{
ClientID: os.Getenv("MASTODON_CLIENT_ID"),
ClientSecret: os.Getenv("MASTODON_CLIENT_SECRET"),
InstanceURL: os.Getenv("MASTODON_INSTANCE_URL"),
RedirectURL: cfg.BaseURL + "/oauth/mastodon/callback",
},
LinkedIn: forgesocial.LinkedInConfig{
ClientID: os.Getenv("LINKEDIN_CLIENT_ID"),
ClientSecret: os.Getenv("LINKEDIN_CLIENT_SECRET"),
RedirectURL: cfg.BaseURL + "/oauth/linkedin/callback",
},
})
social.Register(app)
defer social.Stop()
// Wire MCP tools.
mcpSrv := forgemcp.New(app,
forgemcp.WithModule(social.PostModule()),
forgemcp.WithModule(social.CredentialModule()),
)
// Layer 1 — wire agent routing (optional).
// Fires on AfterPublish for "Post" content type.
social.AddRoutes(app,
forgesocial.OnPublish("Post", "https://agent.example.com/social"),
)
Index ¶
- func CreateTables(db forge.DB) error
- type Config
- type LinkedInConfig
- type MastodonConfig
- type PlatformConfig
- type PlatformCredential
- type PostStatus
- type PublicationSchedule
- type Route
- type Router
- type ScheduleStatus
- type ScheduledPost
- type Slot
- type Social
- func (s *Social) AddRoutes(app *forge.App, routes ...Route)
- func (s *Social) ConfigModule() forge.MCPModule
- func (s *Social) CredentialModule() forge.MCPModule
- func (s *Social) PostModule() forge.MCPModule
- func (s *Social) Register(app *forge.App)
- func (s *Social) ScheduleModule() forge.MCPModule
- func (s *Social) Stop()
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CreateTables ¶
CreateTables creates all forge_social_* database tables and indexes. It is safe to call multiple times — all statements use CREATE ... IF NOT EXISTS. Call this once at application startup before any other forge-social operations.
It also applies an idempotent migration that adds the actor_id column to forge_social_credentials for databases created before v0.2.0.
Types ¶
type Config ¶
type Config struct {
// Secret is the application's Config.Secret, used to derive the AES-256-GCM
// key for encrypting stored OAuth tokens. Must match the forge.App's secret.
Secret []byte
// Mastodon holds the Mastodon OAuth 2.0 client credentials.
Mastodon MastodonConfig
// LinkedIn holds the LinkedIn OAuth 2.0 client credentials.
// Leave zero-valued to disable LinkedIn publishing.
LinkedIn LinkedInConfig
}
Config holds the configuration for a Social instance.
type LinkedInConfig ¶ added in v0.2.0
type LinkedInConfig struct {
// ClientID is the LinkedIn OAuth application client ID.
ClientID string
// ClientSecret is the LinkedIn OAuth application client secret.
ClientSecret string
// RedirectURL is the callback URL registered with the LinkedIn application,
// e.g. cfg.BaseURL + "/oauth/linkedin/callback".
RedirectURL string
// SuccessURL is an optional URL to redirect the user to after a successful
// OAuth connection. If empty, a plain confirmation response is returned.
SuccessURL string
}
LinkedInConfig holds OAuth 2.0 client credentials for the LinkedIn platform.
type MastodonConfig ¶
type MastodonConfig struct {
// ClientID is the OAuth 2.0 client_id issued by the Mastodon instance.
ClientID string
// ClientSecret is the OAuth 2.0 client_secret issued by the Mastodon instance.
ClientSecret string
// InstanceURL is the base URL of the Mastodon instance, e.g. "https://mastodon.social".
InstanceURL string
// RedirectURL is the OAuth callback URL registered with the Mastodon instance.
// Set this to your app's BaseURL + "/oauth/mastodon/callback".
RedirectURL string
// SuccessURL is an optional URL to redirect the browser to after a
// successful OAuth callback. If empty, a plain HTML confirmation is shown.
SuccessURL string
// Scopes is the list of OAuth 2.0 scopes to request. Defaults to
// ["write:statuses", "write:media"] when empty.
Scopes []string
}
MastodonConfig holds the OAuth 2.0 client credentials for a Mastodon instance. Register your application once on the Mastodon instance admin panel and supply the resulting client_id and client_secret here.
type PlatformConfig ¶ added in v0.5.0
type PlatformConfig struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
RedirectURL string `json:"redirect_url"`
// InstanceURL is the Mastodon instance base URL (e.g. https://mastodon.social).
// Empty for all other platforms.
InstanceURL string `json:"instance_url,omitempty"`
// SuccessURL is an optional redirect URL shown after a successful OAuth callback.
SuccessURL string `json:"success_url,omitempty"`
}
PlatformConfig holds the operator-supplied OAuth 2.0 app credentials for a social platform. One row per platform in forge_social_platform_config.
type PlatformCredential ¶
type PlatformCredential struct {
ID string `json:"id"`
Platform string `json:"platform"`
Name string `json:"name"`
InstanceURL string `json:"instance_url"`
// ActorID is the platform-specific author identifier used when publishing.
// For LinkedIn this is the person URN ("urn:li:person:{sub}").
// For Mastodon it is unused and stored as an empty string.
ActorID string `json:"actor_id,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// contains filtered or unexported fields
}
PlatformCredential stores OAuth 2.0 credentials for a social platform. AccessToken and RefreshToken are stored encrypted in the database and are never exposed through MCP responses.
type PostStatus ¶
type PostStatus string
PostStatus represents the lifecycle state of a ScheduledPost.
const ( // PostStatusDraft is the initial state. scheduled_at may be nil. PostStatusDraft PostStatus = "draft" // PostStatusScheduled means the post has a scheduled_at in the future // and will be published by the internal scheduler. PostStatusScheduled PostStatus = "scheduled" // PostStatusPublished means the post has been successfully sent to the platform. PostStatusPublished PostStatus = "published" // PostStatusFailed means a terminal publish error occurred. PostStatusFailed PostStatus = "failed" // PostStatusArchived means the post has been manually archived. PostStatusArchived PostStatus = "archived" // PostStatusQueued means the post is waiting for the next available slot // in a PublicationSchedule. It has no scheduled_at and will be published // by the slot-queue scheduler when a slot fires for its credential. PostStatusQueued PostStatus = "queued" )
type PublicationSchedule ¶ added in v0.4.0
type PublicationSchedule struct {
ID string `json:"id"`
CredentialID string `json:"credential_id"`
Slots []Slot `json:"slots"`
Status ScheduleStatus `json:"status"`
LastTickAt *time.Time `json:"last_tick_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
PublicationSchedule defines a recurring set of time slots for automatically publishing queued posts for a specific credential.
Each credential may have at most one PublicationSchedule. Use Social.ScheduleModule to expose this type via MCP tools.
func (PublicationSchedule) GetSlug ¶ added in v0.4.0
func (ps PublicationSchedule) GetSlug() string
GetSlug satisfies the slugger interface used by forge-mcp's allResources.
type Route ¶ added in v0.3.0
type Route struct {
// Signal is the Forge lifecycle signal this route responds to.
Signal forge.Signal
// ContentType is the Go type name of the content type (e.g. "Post", "Story").
// Matching is exact. Use the PascalCase struct name exactly as it appears
// in your content type definition.
ContentType string
// AgentURL is the HTTPS endpoint that receives the signed JSON payload.
// Validated at [AddRoutes] time — must be HTTPS and not a private address.
AgentURL string
}
Route associates a lifecycle signal and content type with an agent URL. When Forge fires the matching signal for the matching content type, the Router enqueues an outbound HTTP POST to AgentURL.
Use the builder functions OnPublish, OnSchedule, OnArchive, and OnDelete to construct Route values.
func OnArchive ¶ added in v0.3.0
OnArchive returns a Route that fires on forge.AfterArchive for the named content type.
func OnDelete ¶ added in v0.3.0
OnDelete returns a Route that fires on forge.AfterDelete for the named content type.
func OnPublish ¶ added in v0.3.0
OnPublish returns a Route that fires on forge.AfterPublish for the named content type. agentURL must be a public HTTPS URL (validated at [AddRoutes] time).
func OnSchedule ¶ added in v0.3.0
OnSchedule returns a Route that fires on forge.AfterSchedule for the named content type.
type Router ¶ added in v0.3.0
type Router struct {
// contains filtered or unexported fields
}
Router holds the registered routes and the route delivery worker. It is created by [AddRoutes] and owned by Social.
type ScheduleStatus ¶ added in v0.4.0
type ScheduleStatus string
ScheduleStatus represents whether a PublicationSchedule is actively firing.
const ( // ScheduleStatusActive means the schedule fires slots and dequeues posts. ScheduleStatusActive ScheduleStatus = "active" // ScheduleStatusPaused means the schedule exists but does not fire. ScheduleStatusPaused ScheduleStatus = "paused" )
type ScheduledPost ¶
type ScheduledPost struct {
ID string `json:"id"`
Platform string `json:"platform"`
CredentialID string `json:"credential_id"`
Body string `json:"body"`
MediaURL string `json:"media_url,omitempty"`
AltText string `json:"alt_text,omitempty"`
ScheduledAt *time.Time `json:"scheduled_at,omitempty"`
Status PostStatus `json:"status"`
PlatformPostID string `json:"platform_post_id,omitempty"`
ErrorMsg string `json:"error_msg,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
ScheduledPost represents a piece of content to be published to a social platform. Use Social.PostModule to expose ScheduledPost via MCP tools.
func (ScheduledPost) GetSlug ¶
func (p ScheduledPost) GetSlug() string
GetSlug satisfies the slugger interface used by forge-mcp's allResources.
type Slot ¶ added in v0.4.0
type Slot struct {
// Weekday is the day of the week (0=Sunday … 6=Saturday, matches time.Weekday).
Weekday int `json:"weekday"`
// Time is the wall-clock time in 24-hour HH:MM format, e.g. "09:00".
Time string `json:"time"`
// Timezone is an IANA timezone name, e.g. "Europe/Copenhagen".
Timezone string `json:"timezone"`
}
Slot defines a recurring publication time within a PublicationSchedule.
type Social ¶
type Social struct {
// contains filtered or unexported fields
}
Social manages platform publishing for a Forge application. Create it with New and register its HTTP routes with [Register]. Optionally register agent routes with [AddRoutes] for Layer 1 routing. Call [Stop] in your application's shutdown handler.
func New ¶
New creates a Social instance backed by db. It panics if db is nil, if Config.Secret is empty, or if the database tables cannot be created.
func (*Social) AddRoutes ¶ added in v0.3.0
AddRoutes registers routes on the Social instance and wires each unique signal to the Forge App's signal bus. It also starts the route delivery worker goroutine.
Call AddRoutes before [app.Run]. Panics if any route has an invalid ContentType or AgentURL (see Route for validation rules).
Layer 1 (AddRoutes) and Layer 2 (Register) are independent — you may call either, both, or neither.
func (*Social) ConfigModule ¶ added in v0.5.0
ConfigModule returns a forge.MCPModule that exposes the configure_platform admin tool for storing per-platform OAuth 2.0 app credentials in the DB. Pass it to forgemcp.WithModule when wiring the MCP server. Only users with Admin role can call the configure_platform tool.
func (*Social) CredentialModule ¶
CredentialModule returns a forge.MCPModule that exposes PlatformCredential as MCP tools (create/connect, list, get, delete). Pass it to forgemcp.WithModule when wiring the MCP server.
func (*Social) PostModule ¶
PostModule returns a forge.MCPModule that exposes ScheduledPost as MCP tools (create, update, publish, archive, delete, list, get). Pass it to forgemcp.WithModule when wiring the MCP server.
func (*Social) Register ¶
Register mounts the forge-social HTTP routes on app and starts the internal scheduler goroutine.
Routes registered:
GET /oauth/mastodon/callback — OAuth 2.0 callback from Mastodon GET /oauth/linkedin/callback — OAuth 2.0 callback from LinkedIn (when configured) GET /oauth/x/callback — OAuth 2.0 + PKCE callback from X (when configured)
Call Social.Stop in your shutdown handler to drain the scheduler.
func (*Social) ScheduleModule ¶ added in v0.4.0
ScheduleModule returns a forge.MCPModule that exposes PublicationSchedule as MCP tools (create, update, get, list, delete). Pass it to forgemcp.WithModule when wiring the MCP server.