apps

package
v0.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 15, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

App apps installs Supermarket Apps into bot workspaces. A Package bundles Skills, workspace dependency references, and Connect-It connector references; the service materializes the Skills itself and delegates dependencies and connectors to their own services, keeping one shared copy of each per bot.

Index

Constants

View Source
const (
	EventStarted  = "started"
	EventStep     = "step"
	EventLog      = "log"
	EventStepDone = "step_done"
	EventDone     = "done"
	EventError    = "error"
)

Event types emitted while an App operation runs.

View Source
const (
	KindDependency = "dependency"
	KindSkills     = "skills"
	KindConnector  = "connector"
	KindApp        = "app"
)

Step kinds: the component a step works on.

View Source
const (
	StepInstalled    = "installed"
	StepUpdated      = "updated"
	StepLinked       = "linked"
	StepNeedsAuth    = "needs_auth"
	StepFailed       = "failed"
	StepSkipped      = "skipped"
	StepRemoved      = "removed"
	StepKept         = "kept"
	StepDisconnected = "disconnected"
	// StepUnlinked means an App reference to a connection was dropped while
	// the bot-level connection stays authorized.
	StepUnlinked = "unlinked"
)

Step outcomes.

View Source
const (
	RemovalActionRemove     = "remove"
	RemovalActionKeep       = "keep"
	RemovalActionDisconnect = "disconnect"
	RemovalActionNone       = "none"

	RemovalReasonShared = "shared"
	RemovalReasonImage  = "image"
	RemovalReasonAbsent = "absent"
)

Removal actions and reasons reported by RemovalPreview.

View Source
const DependencyRegistryID = "memoh"

DependencyRegistryID is the only registry whose Apps may reference workspace dependencies and connectors.

Variables

View Source
var (
	// ErrInvalidRequest means the request names an invalid App, revision
	// or reference.
	ErrInvalidRequest = errors.New("app request is invalid")
	// ErrConnectorNotReferenced means the installation does not reference the
	// connector type.
	ErrConnectorNotReferenced = errors.New("app does not reference this connector")
	// ErrDependenciesUnavailable means the App needs workspace
	// dependencies but no dependency service is configured.
	ErrDependenciesUnavailable = errors.New("workspace dependency service is not configured")
)

Sentinel errors returned by Service.

View Source
var ErrNotInstalled = errors.New("app is not installed")

ErrNotInstalled is returned by lookups for unknown installations.

Functions

func NewSupermarketPublisher

func NewSupermarketPublisher(installer *supermarket.Installer) interface {
	SkillPublisher
	RegistryClient
}

NewSupermarketPublisher exposes a Supermarket installer as the Skill publisher and registry client of the apps service.

Types

type BotConnectorRef

type BotConnectorRef struct {
	ConnectorRef
	RegistryID string
	AppID      string
}

BotConnectorRef is a ConnectorRef joined with its App identity.

type BotDependencyRef

type BotDependencyRef struct {
	DependencyRef
	RegistryID string
	AppID      string
}

BotDependencyRef is a DependencyRef joined with its App identity.

type ConnectorItem

type ConnectorItem struct {
	Type         string
	Required     bool
	ConnectionID string
	// Connector is the bot's linked connection, nil until authorized.
	Connector *connectors.Connector
}

ConnectorItem is one connector reference of an App.

type ConnectorManager

type ConnectorManager interface {
	Configured() bool
	List(ctx context.Context, botID string) ([]connectors.Connector, error)
	BeginOAuth(ctx context.Context, botID, connectorType, authMethod string) (connectsdk.OAuthAuthorization, error)
	CreateCredential(ctx context.Context, botID, connectorType, authMethod string, fields map[string]string) (connectors.Connector, error)
	Delete(ctx context.Context, botID, connectionID string) error
}

ConnectorManager is the slice of *connectors.Service the service uses.

type ConnectorRef

type ConnectorRef struct {
	InstallationID string
	ConnectorType  string
	ConnectionID   string
	Required       bool
}

ConnectorRef links an installation to a Connect-It connector type and, once authorized, to the bot-level connection.

type DependencyItem

type DependencyItem struct {
	ID string
	// Entry is the reconciled dependency, nil when the catalog does not
	// know the ID.
	Entry *workspacedeps.Entry
	// Shared is set when another installed App references the same
	// dependency on this target.
	Shared bool
}

DependencyItem is one dependency reference of an App as seen on a bot workspace.

type DependencyManager

type DependencyManager interface {
	List(ctx context.Context, botID string) (workspacedeps.ListResult, error)
	Refresh(ctx context.Context, botID string) (workspacedeps.ListResult, error)
	CheckUpdates(ctx context.Context, botID string) (workspacedeps.ListResult, error)
	Install(ctx context.Context, botID, depID, version string, sink workspacedeps.LogSink) (workspacedeps.OperationResult, error)
	Update(ctx context.Context, botID, depID, version string, sink workspacedeps.LogSink) (workspacedeps.OperationResult, error)
	Remove(ctx context.Context, botID, depID string, sink workspacedeps.LogSink) (workspacedeps.OperationResult, error)
	// EnsureRunning starts a stopped bot workspace before a mutating step.
	EnsureRunning(ctx context.Context, botID string) error
}

DependencyManager is the slice of *workspacedeps.Service the service uses.

type DependencyRef

type DependencyRef struct {
	InstallationID string
	DependencyID   string
}

DependencyRef links an installation to a workspace dependency ID.

type Event

type Event struct {
	Type    string
	Kind    string
	ID      string
	Stream  string
	Data    string
	Status  string
	Version string
	Message string
}

Event is one progress frame of an App operation. Type selects which fields are meaningful: step and step_done carry Kind and ID, log carries Stream and Data, step_done and done carry Status.

type EventFunc

type EventFunc func(Event)

EventFunc adapts a function to EventSink.

func (EventFunc) Send

func (f EventFunc) Send(event Event)

type EventSink

type EventSink interface {
	Send(Event)
}

EventSink receives operation events.

type InstallRequest

type InstallRequest struct {
	RegistryID string
	AppID      string
	Revision   string

	// Reason defaults to ReasonUser.
	Reason Reason
}

InstallRequest names one immutable App release to install.

type Installation

type Installation struct {
	ID    string
	BotID string

	RegistryID        string
	AppID             string
	Revision          string
	Version           string
	Status            Status
	Reason            Reason
	AvailableRevision string
	AvailableVersion  string
	LastCheckedAt     *time.Time
	LastError         string
	// Release is the immutable release document the installation
	// materialized; it lets the App view work without the Supermarket.
	Release     []byte
	InstalledAt time.Time
	UpdatedAt   time.Time
}

Installation is one row of bot_app_installations.

type Item

type Item struct {
	// Installation is nil for a discovered App.
	Installation *Installation
	RegistryID   string
	AppID        string
	Revision     string
	Version      string
	// Release is the materialized release; nil for discovered Apps and
	// for records whose cached release cannot be decoded.
	Release      *supermarket.AppDescriptor
	Discovered   bool
	Dependencies []DependencyItem
	Connectors   []ConnectorItem
}

Item is one App in a bot's isolated workspace: an installation record with its components, or a dependency the workspace already carries shown through its canonical App.

type ListResult

type ListResult struct {
	Workspace              workspacedeps.WorkspaceState
	DataRoot               string
	DependencyCatalogStale bool
	Items                  []Item
}

ListResult is the App view of one bot's isolated workspace.

type OperationResult

type OperationResult struct {
	Installation Installation
	Steps        []StepResult
}

OperationResult is the receipt of an App operation.

type Options

type Options struct {
	Store        Store
	Registry     RegistryClient
	Skills       SkillPublisher
	Dependencies DependencyManager
	Connectors   ConnectorManager
	Logger       *slog.Logger
	Now          func() time.Time
}

Options configures NewService. Store, Registry and Skills are required; Dependencies and Connectors may be nil when the deployment lacks them.

type Reason

type Reason string

Reason records why an App was installed.

const (
	// ReasonUser means the user installed the App explicitly.
	ReasonUser Reason = "user"
	// ReasonRequired means another App pulled it in as a dependency
	// carrier and nobody asked for it directly.
	ReasonRequired Reason = "required"
)

Installation reasons.

type RegistryClient

type RegistryClient interface {
	FetchRelease(ctx context.Context, registryID, appID, revision string) (supermarket.AppDescriptor, error)
	FetchCurrentApp(ctx context.Context, registryID, appID string) (supermarket.AppDescriptor, error)
}

RegistryClient fetches App descriptors from the Supermarket.

type RemovalPreview

type RemovalPreview struct {
	Installation Installation
	Dependencies []RemovalPreviewDependency
	Connectors   []RemovalPreviewConnector
	// RequiredApps are auto-installed Apps that no other App
	// would reference once this one is gone.
	RequiredApps []Installation
}

RemovalPreview is the plan of an App removal.

type RemovalPreviewConnector

type RemovalPreviewConnector struct {
	Type         string
	ConnectionID string
	Action       string
	Reason       string
}

RemovalPreviewConnector says what removing the App does to one connector reference.

type RemovalPreviewDependency

type RemovalPreviewDependency struct {
	ID     string
	Action string
	Reason string
}

RemovalPreviewDependency says what removing the App does to one dependency reference.

type RemoveOptions

type RemoveOptions struct {
	// RemoveUnreferencedRequired also removes the auto-installed Apps
	// listed by RemovalPreview.RequiredApps.
	RemoveUnreferencedRequired bool
}

RemoveOptions tunes Remove.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service installs, lists, updates and removes Apps for bots.

func NewService

func NewService(opts Options) *Service

NewService wires a Service. It panics when a required option is nil, which is a wiring error.

func (*Service) BeginConnectorOAuth

func (s *Service) BeginConnectorOAuth(ctx context.Context, botID, installationID, connectorType, authMethod string) (connectsdk.OAuthAuthorization, error)

BeginConnectorOAuth starts authorization for a connector the installation references and links the resulting connection to it.

func (*Service) CheckUpdates

func (s *Service) CheckUpdates(ctx context.Context, botID string) (ListResult, error)

CheckUpdates compares every installed App with the registry's current release, records what is available, refreshes the dependency update checks, and returns the refreshed view.

func (*Service) CreateConnectorCredential

func (s *Service) CreateConnectorCredential(ctx context.Context, botID, installationID, connectorType, authMethod string, fields map[string]string) (connectors.Connector, error)

CreateConnectorCredential connects an API-key connector the installation references and links the connection to it.

func (*Service) Get

func (s *Service) Get(ctx context.Context, botID, installationID string) (Item, error)

Get returns one installation with its components.

func (*Service) Install

func (s *Service) Install(ctx context.Context, botID string, req InstallRequest, sink EventSink) (OperationResult, error)

Install materializes an App release into a bot's isolated workspace: it installs missing dependencies, publishes the Skills and links connectors. A dependency failure or an unauthorized required connector leaves the installation partial instead of failing it; a Skill failure fails it.

func (*Service) List

func (s *Service) List(ctx context.Context, botID string, refresh bool) (ListResult, error)

List returns every installed App of a bot workspace together with the canonical Apps of dependencies no installation references.

func (*Service) RemovalPreview

func (s *Service) RemovalPreview(ctx context.Context, botID, installationID string) (RemovalPreview, error)

RemovalPreview reports what Remove would do without changing anything.

func (*Service) Remove

func (s *Service) Remove(ctx context.Context, botID, installationID string, opts RemoveOptions, sink EventSink) (OperationResult, error)

Remove uninstalls an App: its Skills, the dependencies no other App references, and the connections no other App references. Dependency and connector failures retain the installation and unfinished references for an explicit removal retry.

func (*Service) Resume

func (s *Service) Resume(ctx context.Context, botID, installationID string, sink EventSink) (OperationResult, error)

Resume continues a partial installation: dependencies that are still missing are installed again, Skills are reconciled and connectors are linked when a connection appeared since.

func (*Service) Update

func (s *Service) Update(ctx context.Context, botID, installationID string, sink EventSink) (OperationResult, error)

Update moves an installation to the registry's current release. Skills are replaced atomically, new references are linked or installed, dropped dependencies are removed the way Remove would, and dropped connector references are unlinked while the bot-level connection stays authorized. Dependency definitions keep their own update cycle; an App update never reinstalls a dependency that is already present.

func (*Service) UpdateSelection

func (s *Service) UpdateSelection(ctx context.Context, botID string, req UpdateRequest, sink EventSink) (OperationResult, error)

UpdateSelection runs the chosen updates of one App as one stream: the dependencies first, each to its latest version, then the release. A dependency that fails does not stop the others; the release step only runs when it was selected.

type SkillPublisher

type SkillPublisher interface {
	PublishSkills(ctx context.Context, botID string, pkg supermarket.AppDescriptor, expectedRevision string) (SkillTransaction, []supermarket.InstallSkillResponse, error)
	RemoveSkills(ctx context.Context, botID, registryID, appID, revision string) (SkillTransaction, error)
}

SkillPublisher materializes App Skills in a bot workspace.

type SkillTransaction

type SkillTransaction interface {
	Commit(ctx context.Context) error
	Rollback(ctx context.Context) error
}

SkillTransaction is a staged workspace change that the service commits after recording it, or rolls back.

type Status

type Status string

Status is the lifecycle state of an App installation record.

const (
	// StatusInstalled means every component the App needs is in place.
	StatusInstalled Status = "installed"
	// StatusPartial means the Skills are in place but a dependency failed to
	// install or a required connector is not authorized yet.
	StatusPartial Status = "partial"
	// StatusInstalling, StatusUpdating and StatusRemoving are transient
	// operation states.
	StatusInstalling Status = "installing"
	StatusUpdating   Status = "updating"
	StatusRemoving   Status = "removing"
	// StatusFailed means materialization or its reference cleanup failed.
	StatusFailed Status = "failed"
)

Installation statuses.

type StepResult

type StepResult struct {
	Kind    string
	ID      string
	Status  string
	Version string
	Error   string
}

StepResult summarizes one step of a completed operation.

type Store

type Store interface {
	Get(ctx context.Context, botID, registryID, appID string) (Installation, error)
	GetByID(ctx context.Context, botID, installationID string) (Installation, error)
	ListForBot(ctx context.Context, botID string) ([]Installation, error)
	Upsert(ctx context.Context, in UpsertInstallation) (Installation, error)
	SetStatus(ctx context.Context, botID, installationID string, status Status, lastError string) (Installation, error)
	SetRelease(ctx context.Context, botID, installationID, revision, version string, release []byte) (Installation, error)
	SetCheck(ctx context.Context, botID, installationID, availableRevision, availableVersion string, checkedAt time.Time) (Installation, error)
	Delete(ctx context.Context, botID, installationID string) (Installation, error)

	ListDependencyRefs(ctx context.Context, installationID string) ([]DependencyRef, error)
	ListBotDependencyRefs(ctx context.Context, botID string) ([]BotDependencyRef, error)
	AddDependencyRef(ctx context.Context, installationID, dependencyID string) error
	RemoveDependencyRef(ctx context.Context, installationID, dependencyID string) error

	ListConnectorRefs(ctx context.Context, installationID string) ([]ConnectorRef, error)
	ListBotConnectorRefs(ctx context.Context, botID string) ([]BotConnectorRef, error)
	UpsertConnectorRef(ctx context.Context, ref ConnectorRef) error
	SetConnectorRefConnection(ctx context.Context, installationID, connectorType, connectionID string) error
	ClearConnectorRefConnection(ctx context.Context, connectionID string) error
	RemoveConnectorRef(ctx context.Context, installationID, connectorType string) error
}

Store persists App installations and their references. Rows are team scoped by row level security on the connection.

func NewPostgresStore

func NewPostgresStore(q dbstore.Queries) Store

NewPostgresStore returns a Store backed by the sqlc queries in q. Team scoping comes from the pooled connection, not from the context.

type UpdateRequest

type UpdateRequest struct {
	RegistryID string
	AppID      string

	// Release moves the installation to the registry's current release.
	Release bool
	// Dependencies are updated to their latest version. Each must be one the
	// App references or, for a discovered canonical App, its own id.
	Dependencies []string
}

UpdateRequest selects what to update for one App in a bot's isolated workspace.

type UpsertInstallation

type UpsertInstallation struct {
	BotID string

	RegistryID string
	AppID      string
	Revision   string
	Version    string
	Status     Status
	Reason     Reason
	Release    []byte
}

UpsertInstallation creates or replaces the identity portion of a record.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL