Documentation
¶
Overview ¶
Package plugins is Ether's plugin host core (SPEC §5.1, §5.4, §5.5, §5.7, §5.13, WS7): manifest parsing and validation, install and lifecycle, permissions and grants, settings and sealed secrets, KV, health, the pull scheduler, the event outbox and log, the journal (shadow and undo), update and rollback, removal, cluster placement, and the owner API.
Runtimes are separate workstreams and plug in through Runtime and RuntimeFactory: WS8a registers the hosted (wazero) runtime, WS8b the remote (URL and tunnel) runtimes. Capability adapters (WS9) call plugins through Manager.Call and read state through Manager's accessors; they never touch the tables directly. The conformance kit (WS11) reuses ParseManifest, Manifest.Validate and LintCopy.
Index ¶
- Constants
- Variables
- func AddonResult(resp Response) (json.RawMessage, error)
- func CollectionPluginID(ctx context.Context) string
- func CompareSemVer(a, b string) int
- func DeadlineFor(path string) time.Duration
- func DescriptorsFor(man Manifest) []extend.Descriptor
- func FetchResult(resp FetchResponse) map[string]any
- func HotLimits(m Manifest) wasm.Limits
- func IsGitHubURL(raw string) bool
- func LintCopy(s string, max int) string
- func LintSettingsSchema(raw json.RawMessage) error
- func NonSecretSettings(settings map[string]any, schema json.RawMessage, declaredSecrets []string) map[string]any
- func NormalizeNotify(kind string) string
- func NormalizePlayback(kind, state string) string
- func ParamFieldsFromList(pluginID string, fields []ListParamField) ([]extend.ParamField, string)
- func ParseSemVer(v string) ([3]int, bool)
- func PermissionDiff(cur, next Manifest) []string
- func PermissionSheet(man Manifest) (lines []string, needsViewers, needsFolders bool)
- func PkgDigest(files map[string][]byte) string
- func StremioCatalogKey(c StremioCat) string
- func StremioInstallID(link string) (id, base string, err error)
- func ToolName(plugin, name string) string
- type AddonCat
- type AddonConfig
- type AddonConfigChange
- type AddonConfigField
- type AddonConfigOption
- type AddonConfigResult
- type AddonFetcher
- type AddonInstall
- type AddonPreview
- type Author
- type Backends
- type CallRecord
- type CandidateFacts
- type Capability
- type Catalogue
- type CatalogueArtifact
- type ChannelsMeta
- type ClientCaps
- type CollectionInputError
- type CommandMeta
- type Contributes
- type Deps
- type Detail
- type DirectoryEntry
- type DirectoryMeta
- type DirectoryResult
- type EtherBlock
- type Event
- type EventsMeta
- type FetchRequest
- type FetchResponse
- type FieldError
- type FolderEntry
- type Grants
- type Health
- type HealthDecl
- type Host
- type HotBudgets
- type HotOutcome
- type HotRuntime
- type InstallOptions
- type Installed
- type IntegrationMeta
- type JournalEntry
- type Kind
- type ListParamField
- type ListSourceMeta
- type Manager
- func (m *Manager) Addon(rec Record) stremio.Addon
- func (m *Manager) AddonConfig(ctx context.Context, id string) (AddonConfig, error)
- func (m *Manager) AddonConfigPage(ctx context.Context, id string) (string, error)
- func (m *Manager) AddonFetch(ctx context.Context, id, route string) (Response, error)
- func (m *Manager) AddonLink(ctx context.Context, id string) (string, error)
- func (m *Manager) AddonLinkConfigPage(link string) (string, error)
- func (m *Manager) ApplyUpdate(ctx context.Context, id string, acceptAdded bool) (Record, error)
- func (m *Manager) BrowseDirectory(ctx context.Context, plugin, key string) (DirectoryResult, error)
- func (m *Manager) Call(ctx context.Context, pluginID string, req Request) (Response, error)
- func (m *Manager) CallStream(ctx context.Context, pluginID string, req Request) (Response, io.ReadCloser, error)
- func (m *Manager) CheckHealth(ctx context.Context, id string) (Health, error)
- func (m *Manager) CheckUpdate(ctx context.Context, id string) (*Preview, bool, error)
- func (m *Manager) Configure(ctx context.Context, id string, incoming map[string]any) (map[string]string, error)
- func (m *Manager) DeliverOutbox(ctx context.Context, pluginID string) error
- func (m *Manager) FetchPickedSubtitle(ctx context.Context, plugin, title, subtitle, token, rawURL string) ([]byte, error)
- func (m *Manager) Fetcher(plugin string) AddonFetcher
- func (m *Manager) Get(ctx context.Context, id string) (Record, error)
- func (m *Manager) GetSettings(ctx context.Context, id string) (map[string]any, json.RawMessage, error)
- func (m *Manager) GrantsOf(ctx context.Context, id string) (Grants, error)
- func (m *Manager) Handler() http.Handler
- func (m *Manager) HealthOf(ctx context.Context, id string) (Health, error)
- func (m *Manager) HostFor(pluginID string) Host
- func (m *Manager) Hot(ctx context.Context, pluginID string) (HotRuntime, bool)
- func (m *Manager) HotReady(pluginID string) (HotRuntime, bool)
- func (m *Manager) Install(ctx context.Context, p *Preview, opts InstallOptions) (Record, error)
- func (m *Manager) InstallAddon(ctx context.Context, in AddonInstall) (Record, error)
- func (m *Manager) Journal(ctx context.Context, id string, limit int, shadowOnly bool) ([]JournalEntry, error)
- func (m *Manager) List(ctx context.Context) ([]Record, error)
- func (m *Manager) MintSubtitlePick(plugin, title, subtitle string) (string, error)
- func (m *Manager) MintSubtitleURLPick(plugin, title, subtitle, rawURL string) (string, error)
- func (m *Manager) OnRemove(fn func(ctx context.Context, id string))
- func (m *Manager) OnSync(fn func(ctx context.Context, r Record))
- func (m *Manager) Options(ctx context.Context, id, field string) (json.RawMessage, error)
- func (m *Manager) PackageFiles(ctx context.Context, id string) (map[string][]byte, error)
- func (m *Manager) PluginSettings(ctx context.Context, pluginID string) (map[string]any, error)
- func (m *Manager) PreviewCatalogGet(ctx context.Context, id string) (json.RawMessage, bool, error)
- func (m *Manager) PreviewCatalogSearch(ctx context.Context, query string, limit, offset int) (json.RawMessage, bool, error)
- func (m *Manager) PreviewFetch(ctx context.Context, network []string, req FetchRequest) (FetchResponse, error)
- func (m *Manager) PreviewInstall(ctx context.Context, src Source) (*Preview, error)
- func (m *Manager) Publish(ctx context.Context, ev Event)
- func (m *Manager) RecordFailure(ctx context.Context, pluginID, reason string)
- func (m *Manager) RecordRanking(ctx context.Context, pluginID string, r RankingReport)
- func (m *Manager) RecordSlow(ctx context.Context, pluginID string, n int)
- func (m *Manager) RegisterRuntime(kind string, f RuntimeFactory)
- func (m *Manager) RelayHandler() http.Handler
- func (m *Manager) Remove(ctx context.Context, id string, undoFirst bool) error
- func (m *Manager) ResolveText(ctx context.Context, plugin, key, locale string) (string, bool)
- func (m *Manager) Revoke(ctx context.Context, id, reason string) (bool, error)
- func (m *Manager) Rollback(ctx context.Context, id string) (Record, error)
- func (m *Manager) Run(ctx context.Context)
- func (m *Manager) SaveAddonConfig(ctx context.Context, id string, ch AddonConfigChange) (Record, error)
- func (m *Manager) SetCatalogue(c Catalogue)
- func (m *Manager) SetEnabled(ctx context.Context, id string, enabled bool) error
- func (m *Manager) SetGrants(ctx context.Context, id string, g Grants) error
- func (m *Manager) SetRoles(ctx context.Context, id string, off []Capability) (Record, error)
- func (m *Manager) SetShadow(ctx context.Context, id string, shadow bool) error
- func (m *Manager) SettingsSchema(ctx context.Context, id string) (json.RawMessage, error)
- func (m *Manager) Start(ctx context.Context) error
- func (m *Manager) StremioResource(ctx context.Context, plugin, resource, typ, id string, extra map[string]string) (Response, error)
- func (m *Manager) SubscribeInvalidations() func()
- func (m *Manager) Test(ctx context.Context, id string) (TestResult, error)
- func (m *Manager) TestAddonConfig(ctx context.Context, id string, ch AddonConfigChange) (AddonConfigResult, error)
- func (m *Manager) TextResolver() extend.TextResolver
- func (m *Manager) UndoAll(ctx context.Context, pluginID string) (int, error)
- func (m *Manager) UndoSince(ctx context.Context, pluginID string, since int64) (int, error)
- type Manifest
- func (m Manifest) AcceptsResource(name, typ, id string) bool
- func (m Manifest) AddonRoles() []Capability
- func (m Manifest) CatalogsOfType(typ string) []StremioCat
- func (m Manifest) ConfigurationRequired() bool
- func (m Manifest) EffectiveEther() *EtherBlock
- func (m Manifest) HasCapability(c Capability) bool
- func (m Manifest) HasResource(name string) bool
- func (m Manifest) IsStremioOnly() bool
- func (m Manifest) RuntimeKind() string
- func (m Manifest) Serves(name, typ string) bool
- func (m Manifest) ServesTV() bool
- func (m Manifest) SpeaksStremio() bool
- func (m Manifest) Stremio() stremio.Manifest
- func (m *Manifest) UnmarshalJSON(b []byte) error
- func (m Manifest) Validate() error
- type MarkersMeta
- type MetadataMeta
- type NotificationMeta
- type PageMeta
- type PermissionIncreaseError
- type Permissions
- type Preview
- type RankingReport
- type RankingStepMeta
- type Record
- type Request
- type Response
- type RoleState
- type RuleConditionMeta
- type Runtime
- type RuntimeDecl
- type RuntimeFactory
- type ScheduleEntry
- type SlotMeta
- type Source
- type SourceMeta
- type StremioCat
- type StremioExtra
- type SubtitlesMeta
- type Summary
- type TestResult
- type ToolMeta
- type ValidationError
- type ViewerPerms
Constants ¶
const ( EventPlaybackStarted = "playback.started" EventPlaybackPaused = "playback.paused" EventPlaybackResumed = "playback.resumed" EventPlaybackStopped = "playback.stopped" EventPlaybackCompleted = "playback.completed" EventPlaybackError = "playback.error" EventPlaybackFailover = "playback.failover" EventTitleAvailable = "title.available" EventViewerAdded = "viewer.added" EventViewerAccess = "viewer.access_changed" EventCollectionRebuilt = "collection.rebuilt" EventServerHealth = "server.health_changed" )
Normalized event names (SPEC §5.7).
const ( KVQuotaBytes = 50 << 20 OutboxCap = 1000 CallsCap = 200 LogsCap = 200 EventLogMaxAge = 7 * 24 * time.Hour MaxFetchBytes = 10 << 20 )
Limits from SPEC §5.1.5, §5.7 and §5.13.
const Protocol = 1
Protocol is the Ether Plugin Protocol major this host speaks (EPP/1).
const RelayPublicPrefix = "/ether/api/addon-relay/"
RelayPublicPrefix is where the console reaches the relay.
const StremioChannelsKey = "channels"
StremioChannelsKey is the channel-source key of a `tv` add-on.
Variables ¶
var ( ErrNotFound = errors.New("plugins: not found") ErrAlreadyInstalled = errors.New("plugins: already installed") ErrPermissionDenied = errors.New("plugins: permission denied") ErrQuotaExceeded = errors.New("plugins: storage quota exceeded") ErrDisabled = errors.New("plugins: plugin is disabled") ErrNoRuntime = errors.New("plugins: no runtime registered for this plugin") ErrShadow = errors.New("plugins: write recorded in shadow mode") ErrDigestMismatch = errors.New("plugins: artifact digest does not match") ErrRevoked = errors.New("plugins: plugin was revoked") )
Sentinel errors. Adapters and the API map them to plain reasons.
var AddonCapabilities = []Capability{CapStreamSource, CapListSource, CapLiveTV, CapSubtitles, CapMetadata, CapPluginDirectory}
AddonCapabilities are the roles a plain Stremio add-on can play.
var ErrFetchFailed = errors.New("plugins: request failed")
ErrFetchFailed is returned when a plugin's outbound request fails. Its message names only the host and a category: request URLs can carry plugin secrets (API keys in the query), and net/http errors include the full URL, so neither the URL nor the underlying error text is exposed.
var ErrNoAddon = errors.New("plugins: this plugin is not bound to an add-on")
ErrNoAddon reports a plugin with no add-on link behind it.
var ErrNoAddonLink = errors.New("plugins: this plugin has no add-on link")
ErrNoAddonLink reports a plugin without a sealed add-on link.
var ErrStreamUnsupported = errors.New("plugins: runtime does not support streaming")
ErrStreamUnsupported indicates that a runtime cannot relay file bodies.
var KnownEvents = map[string]bool{ EventPlaybackStarted: true, EventPlaybackPaused: true, EventPlaybackResumed: true, EventPlaybackStopped: true, EventPlaybackCompleted: true, EventPlaybackError: true, EventPlaybackFailover: true, EventTitleAvailable: true, EventViewerAdded: true, EventViewerAccess: true, EventCollectionRebuilt: true, EventServerHealth: true, }
KnownEvents is the closed v1 event set.
var ReservedCapabilities = map[Capability]bool{ "artwork": true, "ratings": true, "stats_export": true, "sign_in": true, }
Reserved capabilities are known names a manifest may not claim in v1.
Functions ¶
func AddonResult ¶
func AddonResult(resp Response) (json.RawMessage, error)
AddonResult is the guest-facing answer for an add-on fetch made on a draft's behalf (Studio previews).
func CollectionPluginID ¶
CollectionPluginID identifies the installed plugin for a backend write or undo. Only the host supplies this context value; plugin documents cannot set it.
func CompareSemVer ¶
CompareSemVer returns -1, 0 or 1. Unparseable versions compare equal to 0.
func DeadlineFor ¶
DeadlineFor returns the per-route deadline from SPEC §5.1.2.
func DescriptorsFor ¶
func DescriptorsFor(man Manifest) []extend.Descriptor
DescriptorsFor builds the registry descriptors a manifest contributes. Exported for the kit and Studio previews.
func FetchResult ¶
func FetchResult(resp FetchResponse) map[string]any
FetchResult is the guest-facing http.fetch answer. body is the response as text (JSON, HTML, playlists); bodyBase64 carries the exact bytes only for responses that are not valid UTF-8 (archives, images), so a large text response is not sent twice into the 4 MiB host-result cap.
func HotLimits ¶
HotLimits lowers the runtime's hot-path defaults to the tightest budget a manifest declares across its ranking steps. The engine clamps anything above its defaults, so a manifest can lower budgets but never raise them. Studio replay uses it to run a plugin under its installed budgets.
func LintCopy ¶
LintCopy checks one user-visible string against the copy rules: at most max characters (0 means no limit), no em or en dashes, no exclamation marks, no "simply", "just" or "easily", and sentence case. It returns a plain reason, or "" when the copy passes. Shared with the kit (WS11).
func LintSettingsSchema ¶
func LintSettingsSchema(raw json.RawMessage) error
LintSettingsSchema validates a resolved settings schema document (SPEC §5.5 copy rules). Shared with the kit.
func NonSecretSettings ¶
func NonSecretSettings(settings map[string]any, schema json.RawMessage, declaredSecrets []string) map[string]any
NonSecretSettings applies declared defaults, then stored public settings. Explicit zero, false, empty and null values take precedence over defaults. Studio uses the same secret field classifier as installed settings storage.
func NormalizeNotify ¶
NormalizeNotify maps a notify event kind to §5.7 names.
func NormalizePlayback ¶
NormalizePlayback maps a playback.Manager event kind to §5.7 names. state is the raw timeline state for updates (playing, paused, stopped). It returns "" for kinds with no normalized event.
func ParamFieldsFromList ¶
func ParamFieldsFromList(pluginID string, fields []ListParamField) ([]extend.ParamField, string)
func ParseSemVer ¶
ParseSemVer parses a plain major.minor.patch version.
func PermissionDiff ¶
PermissionDiff lists the permissions `next` asks for that `cur` does not have. A non-empty result pauses auto-update and asks the owner.
func PermissionSheet ¶
PermissionSheet returns the plain-language lines the owner sees at install (SPEC §5.4). needsViewers and needsFolders say the sheet needs viewer or folder picks.
func PkgDigest ¶
PkgDigest computes an .etherpkg digest over its files (excluding the digest entry itself). pack (WS11) writes it; install verifies it.
func StremioCatalogKey ¶
func StremioCatalogKey(c StremioCat) string
StremioCatalogKey is the list-source key of a Stremio catalog.
func StremioInstallID ¶
StremioInstallID is the record id of a plain Stremio add-on installed from link, and the normalised base URL it is reached at. The id depends on the link alone: the same link pasted on any page is the same add-on, even when its manifest changes, and two configurations of one add-on (two debrid accounts) are two add-ons.
Types ¶
type AddonCat ¶
type AddonCat struct {
Key string `json:"key"`
Type string `json:"type"`
ID string `json:"id"`
Name string `json:"name"`
}
AddonCat is one catalog an add-on lists, for pickers.
type AddonConfig ¶
type AddonConfig struct {
Configurable bool `json:"configurable"`
Required bool `json:"required"`
Configured bool `json:"configured"`
Layer string `json:"layer"` // declared, decoded, page, none
Fields []AddonConfigField `json:"fields"`
Host string `json:"host"`
}
AddonConfig describes how an add-on is configured, for the console.
type AddonConfigChange ¶
AddonConfigChange is either new values for the drawn fields or a whole install link (from the add-on's own configure page, or pasted).
type AddonConfigField ¶
type AddonConfigField struct {
Key string `json:"key"`
Label string `json:"label"`
Kind string `json:"kind"` // text, number, switch, list, secret, select, fixed
Value any `json:"value,omitempty"`
Set bool `json:"set,omitempty"` // a secret has a value (never sent)
Options []AddonConfigOption `json:"options,omitempty"`
Required bool `json:"required,omitempty"`
Summary string `json:"summary,omitempty"` // fixed (structured) values, described
// Group names the nested setting a field belongs to ("Languages"); its
// Key is then a path ("languages/preferred").
Group string `json:"group,omitempty"`
}
AddonConfigField is one setting as the console draws it.
type AddonConfigOption ¶
AddonConfigOption is one choice of a select field.
type AddonConfigResult ¶
type AddonConfigResult struct {
Name string `json:"name"`
Added []string `json:"added,omitempty"` // catalogues it would add
Removed []string `json:"removed,omitempty"` // catalogues it would drop
Roles []string `json:"roles"` // what it would do in Ether
Sample string `json:"sample,omitempty"` // a live result, in words
Problems []string `json:"problems,omitempty"`
}
AddonConfigResult is what a configuration would change, before saving.
type AddonFetcher ¶
type AddonFetcher struct {
// contains filtered or unexported fields
}
AddonFetcher reads an installed add-on's routes through Call, so every request is guarded, metered, redacted and counted in its health.
type AddonInstall ¶
type AddonInstall struct {
Link string
Name string
Roles []Capability
Offline []string
// Exclusive turns every other role off on a newly created record
// (migrations keep exactly what the legacy entry did).
Exclusive bool
}
AddonInstall is one request to install (or reuse) the add-on at Link and switch Roles on. Name is a fallback display name when the manifest cannot be read; Offline lists the resources a legacy entry proves the add-on serves, used to record it while its host is unreachable.
type AddonPreview ¶
type AddonPreview struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Logo string `json:"logo,omitempty"`
Version string `json:"version,omitempty"`
Host string `json:"host"`
Roles []RoleState `json:"roles"`
Catalogs []AddonCat `json:"catalogs,omitempty"`
AlreadyInstalled bool `json:"alreadyInstalled,omitempty"`
ConfigureFirst bool `json:"configureFirst,omitempty"`
}
AddonPreview is what the console shows before adding a Stremio add-on: the add-on, the roles it can play, and whether that link is already installed (adding it again only switches roles on).
type Backends ¶
type Backends struct {
CatalogSearch func(ctx context.Context, query string, limit, offset int) (json.RawMessage, error)
CatalogGet func(ctx context.Context, id string) (json.RawMessage, error)
ViewerHistory func(ctx context.Context, viewerID int64, limit, offset int) (json.RawMessage, error)
ViewerNames func(ctx context.Context, ids []int64) (json.RawMessage, error)
// SetWatchState applies a watch-state write and returns its inverse
// (the previous state) for the journal.
SetWatchState func(ctx context.Context, viewerID int64, titleID string, watched bool) (previous bool, err error)
// CollectionsUpsert creates or updates a collection and returns the
// previous document (empty when new) for the journal.
CollectionsUpsert func(ctx context.Context, doc json.RawMessage) (previous json.RawMessage, err error)
// CollectionsDelete removes a collection by the id in its document;
// used by undo for a create.
CollectionsDelete func(ctx context.Context, doc json.RawMessage) error
// Notice posts a console notice ("console notice" in SPEC §5.2).
Notice func(text string)
}
Backends are the Ether services host calls end in. Any may be nil; the matching host call then returns ErrUnavailable. App wiring fills them.
type CallRecord ¶
type CallRecord struct {
ID int64 `json:"id"`
Plugin string `json:"plugin"`
Route string `json:"route"`
Method string `json:"method"`
Status int `json:"status"`
MS int64 `json:"ms"`
Error string `json:"error,omitempty"`
Request string `json:"request,omitempty"`
Response string `json:"response,omitempty"`
Created time.Time `json:"created"`
}
CallRecord is one inspector entry (redacted, capped per plugin).
type CandidateFacts ¶
type CandidateFacts struct {
ReleaseID string `json:"releaseId"`
Name string `json:"name"`
Size int64 `json:"size,omitempty"`
Protocol string `json:"protocol,omitempty"` // usenet|torrent|direct
SourceClass string `json:"sourceClass,omitempty"`
Indexer string `json:"indexer,omitempty"`
Resolution string `json:"resolution,omitempty"`
HDR []string `json:"hdr,omitempty"`
VideoCodec string `json:"videoCodec,omitempty"`
AudioCodecs []string `json:"audioCodecs,omitempty"`
AudioChannels string `json:"audioChannels,omitempty"`
Languages []string `json:"languages,omitempty"`
Subtitles []string `json:"subtitles,omitempty"`
ReleaseType string `json:"releaseType,omitempty"`
Group string `json:"group,omitempty"`
Cached bool `json:"cached,omitempty"`
Verified bool `json:"verified,omitempty"`
ClientCaps ClientCaps `json:"clientCaps,omitempty"`
}
CandidateFacts is the hot-path input for ranking steps and rule conditions (SPEC §5.8), JSON-encoded. It never carries viewer data.
type Capability ¶
type Capability string
Capability is one thing a plugin can do (SPEC §5.1.3).
const ( CapStreamSource Capability = "stream_source" CapDebridProvider Capability = "debrid_provider" CapListSource Capability = "list_source" CapMetadata Capability = "metadata" CapPluginDirectory Capability = "plugin_directory" CapLiveTV Capability = "livetv_channels" CapSubtitles Capability = "subtitles" CapMarkers Capability = "markers" CapNotify Capability = "notify" CapEvents Capability = "events" CapRankingStep Capability = "ranking_step" CapRuleCondition Capability = "rule_condition" CapTools Capability = "tools" CapUI Capability = "ui" )
type Catalogue ¶
type Catalogue interface {
http.Handler
// Resolve looks up a plugin in the verified catalogue by plugin ID (or
// artifact URL) and optional version (empty means latest). It fails when
// the plugin is not in the catalogue or is revoked.
Resolve(ctx context.Context, idOrURL, version string) (CatalogueArtifact, error)
}
Catalogue is the signed catalogue hook used by the owner API, install and update flows (WS12).
type CatalogueArtifact ¶
type CatalogueArtifact struct {
ID string
Version string
URL string
SHA256 string
Kind Kind
Permissions Permissions
Capabilities []Capability
}
CatalogueArtifact is a resolved version from the signed plugin catalogue (WS12).
type ChannelsMeta ¶
ChannelsMeta is mandatory for livetv_channels.
type ClientCaps ¶
type ClientCaps struct {
MaxHeight int `json:"maxHeight,omitempty"`
HDR []string `json:"hdr,omitempty"`
Codecs []string `json:"codecs,omitempty"`
}
ClientCaps is what the playing client can show.
type CollectionInputError ¶
type CollectionInputError struct{ Message string }
CollectionInputError is a safe, actionable validation failure supplied by the collection backend. It survives the hosted runtime as a client error.
func (*CollectionInputError) Error ¶
func (e *CollectionInputError) Error() string
type CommandMeta ¶
type CommandMeta struct {
Key string `json:"key"`
Label string `json:"label"`
Action string `json:"action"` // plugin action name
}
CommandMeta is one contributed ⌘K command.
type Contributes ¶
type Contributes struct {
Directories []DirectoryMeta `json:"directories,omitempty"`
Metadata *MetadataMeta `json:"metadata,omitempty"`
Source *SourceMeta `json:"source,omitempty"`
Channels *ChannelsMeta `json:"channels,omitempty"`
Subtitles *SubtitlesMeta `json:"subtitles,omitempty"`
Markers *MarkersMeta `json:"markers,omitempty"`
Notification *NotificationMeta `json:"notification,omitempty"`
Events *EventsMeta `json:"events,omitempty"`
Integration *IntegrationMeta `json:"integration,omitempty"`
ListSources []ListSourceMeta `json:"listSources,omitempty"`
RankingSteps []RankingStepMeta `json:"rankingSteps,omitempty"`
RuleConditions []RuleConditionMeta `json:"ruleConditions,omitempty"`
Tools []ToolMeta `json:"tools,omitempty"`
Pages []PageMeta `json:"pages,omitempty"`
Slots []SlotMeta `json:"slots,omitempty"`
Commands []CommandMeta `json:"commands,omitempty"`
}
Contributes carries per-capability metadata and UI contributions.
type Deps ¶
type Deps struct {
DB *sql.DB
Sealer config.FieldSealer
Registry *extend.Registry
Tools *tools.Catalogue
Notifications *notify.Service
Logger *slog.Logger
// IsLeader reports cluster leadership; nil means always leader.
IsLeader func() bool
// Bus broadcasts invalidate:plugins; nil disables it.
Bus clusterbus.Bus
// FetchClient fetches manifests and artifacts; nil builds one from
// safefetch and egress CapPlugins. Tests inject an httptest client.
FetchClient *http.Client
// CheckPackage runs the conformance kit during install previews.
CheckPackage func(context.Context, []byte, map[string][]byte) error
Backends Backends
Now func() time.Time
}
Deps are the plugin host's explicit dependencies.
type Detail ¶
type Detail struct {
Summary
Manifest Manifest `json:"manifest"`
Permissions struct {
Lines []string `json:"lines"`
Declared Permissions `json:"declared"`
Grants Grants `json:"grants"`
NeedsViewers bool `json:"needsViewers"`
NeedsFolders bool `json:"needsFolders"`
} `json:"permissions"`
HealthDetail Health `json:"healthDetail"`
Privacy struct {
DeclaredHosts []string `json:"declaredHosts"`
ObservedHosts map[string]int `json:"observedHosts"`
Undeclared []string `json:"undeclared,omitempty"`
} `json:"privacy"`
Impact struct {
Calls int `json:"calls"`
Errors int `json:"errors"`
P50MS int64 `json:"p50Ms"`
P95MS int64 `json:"p95Ms"`
EgressBytes int64 `json:"egressBytes"`
KVBytes int64 `json:"kvBytes"`
Slow int64 `json:"slow"`
EventDrops int64 `json:"eventDrops"`
Restarts int64 `json:"restarts"`
} `json:"impact"`
// AddedPermissions is set when an update is waiting and asks for more.
AddedPermissions []string `json:"addedPermissions,omitempty"`
}
Detail is the plugin drawer payload: overview, permissions, health, the privacy label and impact.
type DirectoryEntry ¶
type DirectoryEntry struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Version string `json:"version,omitempty"`
ManifestURL string `json:"manifestURL,omitempty"`
Unsupported string `json:"unsupported,omitempty"`
}
DirectoryEntry is a discovery suggestion from a native or adapted provider. ManifestURL must pass the normal fetch/preview/install policy before use. Directory claims never confer verified status or install permissions.
type DirectoryMeta ¶
DirectoryMeta declares a protocol-neutral plugin discovery source. Entries are suggestions, never installation authorization or verification.
type DirectoryResult ¶
type DirectoryResult struct {
Entries []DirectoryEntry `json:"entries"`
}
type EtherBlock ¶
type EtherBlock struct {
Protocol int `json:"protocol"`
// Stremio marks a native plugin that answers Stremio add-on routes,
// such as an add-on opened and edited in Studio: Ether talks to it
// exactly as to the add-on it came from.
Stremio bool `json:"stremio,omitempty"`
Kind Kind `json:"kind"`
Capabilities []Capability `json:"capabilities,omitempty"`
// Summary is plain text or a "$t:key" reference into Strings.
Summary string `json:"summary,omitempty"`
Author Author `json:"author,omitempty"`
License string `json:"license,omitempty"`
Repo string `json:"repo,omitempty"`
Icon string `json:"icon,omitempty"`
Runtime RuntimeDecl `json:"runtime"`
// Cluster is "leader" (default) or "every_node".
Cluster string `json:"cluster,omitempty"`
Health HealthDecl `json:"health,omitempty"`
Permissions Permissions `json:"permissions,omitempty"`
// Settings is a settings schema (SPEC §5.5), {} or {"$ref":"file"}.
Settings json.RawMessage `json:"settings,omitempty"`
// Strings maps a locale to a file path (string) or an inline
// key-to-text object. "en" is required when any $t: key is used.
Strings map[string]json.RawMessage `json:"strings,omitempty"`
Schedule []ScheduleEntry `json:"schedule,omitempty"`
Contributes Contributes `json:"contributes,omitempty"`
}
EtherBlock is the `ether` object of a manifest.
type Event ¶
type Event struct {
ID string `json:"id"`
Name string `json:"name"`
At time.Time `json:"at"`
ViewerID int64 `json:"viewerId,omitempty"`
Payload json.RawMessage `json:"payload,omitempty"`
}
Event is one normalized Ether event (SPEC §5.7). Payload is JSON with no secrets; viewer identity appears only for plugins granted it (the host strips it per plugin at delivery).
type EventsMeta ¶
type EventsMeta struct {
Subscribe []string `json:"subscribe"`
}
EventsMeta is mandatory for events.
type FetchRequest ¶
type FetchRequest struct {
Method string `json:"method"`
URL string `json:"url"`
Headers map[string]string `json:"headers,omitempty"`
Body []byte `json:"body,omitempty"`
}
FetchRequest is one plugin outbound HTTP call.
type FetchResponse ¶
type FetchResponse struct {
Status int `json:"status"`
Headers map[string]string `json:"headers,omitempty"`
Body []byte `json:"body,omitempty"`
}
FetchResponse is the answer to a FetchRequest (body capped at 10 MiB).
type FieldError ¶
FieldError is one validation problem, keyed by a dotted field path.
type FolderEntry ¶
type FolderEntry struct {
Name string `json:"name"`
Path string `json:"path"`
Dir bool `json:"dir"`
Size int64 `json:"size,omitempty"`
Mtime int64 `json:"mtime,omitempty"` // unix seconds
}
FolderEntry is one entry from FoldersList or FoldersStat.
type Grants ¶
type Grants struct {
Viewers []int64 `json:"viewers,omitempty"`
Folders []string `json:"folders,omitempty"`
Revoked []string `json:"revoked,omitempty"`
LAN bool `json:"lan,omitempty"`
}
Grants is what the owner has granted one plugin on top of its manifest permissions. Revoked lists permission keys the owner has taken back ("network", "catalog", "viewers.identity", "viewers.watch_history", "viewers.write_watch_state", "collections", "folders", "secrets", "events").
type Health ¶
type Health struct {
Status string `json:"status"` // ok|attention|error|disabled
Reason string `json:"reason,omitempty"`
Failures []int64 `json:"-"` // unix seconds, pruned to 10 minutes
Restarts int64 `json:"restarts"`
Slow int64 `json:"slow"`
Drops int64 `json:"drops"`
LastError string `json:"lastError,omitempty"`
LastOK time.Time `json:"lastOk,omitempty"`
NextRetry time.Time `json:"nextRetry,omitempty"`
Observed map[string]int `json:"observed,omitempty"` // host -> fetch count
EgressBytes int64 `json:"egressBytes"`
// RankingSkipped counts the resolves since the plugin's last complete
// ranking that left its ranking step out because it ran past its time
// budget; zero once a ranking finishes in time again.
RankingSkipped int64 `json:"rankingSkipped"`
RankingSkippedAt time.Time `json:"rankingSkippedAt,omitempty"`
}
Health is one plugin's health and impact record.
type HealthDecl ¶
type HealthDecl struct {
Interval string `json:"interval,omitempty"`
}
HealthDecl declares the health-check interval (minimum 15s).
type Host ¶
type Host interface {
KVGet(ctx context.Context, key string) ([]byte, bool, error)
KVPut(ctx context.Context, key string, value []byte) error
KVDelete(ctx context.Context, key string) error
KVList(ctx context.Context, prefix string) ([]string, error)
// SecretGet returns a sealed setting the manifest declared in
// permissions.secrets. Hosted plugins only.
SecretGet(ctx context.Context, name string) (string, error)
// HTTPFetch fetches through egress and safefetch; only manifest
// network hosts are allowed. Observed hosts feed the privacy label.
HTTPFetch(ctx context.Context, req FetchRequest) (FetchResponse, error)
// CatalogSearch and CatalogGet need catalog: read. Results are JSON
// title summaries produced by the injected catalog backend.
CatalogSearch(ctx context.Context, query string, limit, offset int) (json.RawMessage, error)
CatalogGet(ctx context.Context, id string) (json.RawMessage, error)
// ViewerHistory needs viewers.watch_history for that viewer.
ViewerGranted(ctx context.Context) (json.RawMessage, error)
ViewerHistory(ctx context.Context, viewerID int64, limit, offset int) (json.RawMessage, error)
// SetWatchState needs viewers.write_watch_state; journalled.
SetWatchState(ctx context.Context, viewerID int64, titleID string, watched bool) error
// CollectionsUpsert needs collections: write; journalled.
CollectionsUpsert(ctx context.Context, collection json.RawMessage) error
// FoldersList and FoldersStat need folders: read and an owner-picked
// root. They never return file contents.
FoldersList(ctx context.Context, root, path string) ([]FolderEntry, error)
FoldersStat(ctx context.Context, root, path string) (FolderEntry, error)
// Settings returns the plugin's current non-secret settings. Plugins
// read them per request instead of keeping them in instance memory,
// because hosted plugins run in a pool of instances that restart.
// Secrets stay behind SecretGet.
Settings(ctx context.Context) (map[string]any, error)
// NotifyOwner posts a console notice (rate-limited).
NotifyOwner(ctx context.Context, text string) error
// Log appends to the plugin's log ring (redacted, rate-limited).
Log(ctx context.Context, level, msg string, attrs map[string]any) error
}
Host is the set of Ether services a plugin may call (SPEC §5.1.5). Every method re-checks the plugin's live grants, so a revoke takes effect mid-call. Writes are journalled; in shadow mode they are recorded without applying. The hosted runtime exposes Host as imports; remote plugins reach it over /ether/plugin-host/* (WS8b).
type HotBudgets ¶
type HotBudgets struct {
PerCandidate time.Duration `json:"perCandidateNs"`
PerBatch time.Duration `json:"perBatchNs"`
}
HotBudgets are the effective hot-path limits for one plugin.
func EffectiveBudgets ¶
func EffectiveBudgets(lim wasm.Limits) HotBudgets
EffectiveBudgets mirrors the engine's clamping: the budgets a manifest gets as SPEC 5.2 states them, in reference-machine time. The engine scales them by its measured speed (wasm.HotScale); Budgets reports that.
type HotOutcome ¶
type HotOutcome struct {
// Status is ok, error, timeout, forbidden, aborted or governance.
Status string `json:"status"`
Duration time.Duration `json:"durationNs"`
Units int64 `json:"units"`
// Slow counts candidates that went neutral on budget.
Slow int `json:"slow"`
MemoHits int `json:"memoHits"`
Trap bool `json:"trap,omitempty"`
}
HotOutcome classifies one hot-path call for health and replay.
func (HotOutcome) Timeout ¶
func (o HotOutcome) Timeout() bool
Timeout reports whether the call ran out of time or budget.
type HotRuntime ¶
type HotRuntime interface {
Runtime
// RankBatch returns one key per candidate (higher ranks first). A
// candidate that exceeded its budget gets the neutral key 0 and counts
// in HotOutcome.Slow; a batch that ran out of time returns neutral keys
// for the rest.
RankBatch(ctx context.Context, cands []CandidateFacts, config json.RawMessage) (keys []int64, out HotOutcome, err error)
// CondMatch evaluates a rule condition; false when the budget runs out.
CondMatch(ctx context.Context, cand CandidateFacts, operator string, value json.RawMessage) (match bool, out HotOutcome, err error)
HasRankKey() bool
HasCondMatch() bool
// Budgets reports the effective per-candidate and per-batch limits.
Budgets() HotBudgets
}
HotRuntime is implemented by hosted runtimes whose plugin exports the hot-path ABI (SPEC §5.2): ranking steps and rule conditions. The ranking adapters reach it through Manager.Hot. Budgets are the manifest's (lowered, never raised) and every call reports a classified outcome.
type InstallOptions ¶
type InstallOptions struct {
Grants Grants
Settings map[string]any
AutoUpdate bool
Shadow bool
// AcceptAddedPermissions confirms an update that asks for more.
AcceptAddedPermissions bool
}
InstallOptions carries the owner's install-time picks.
type Installed ¶
type Installed struct {
ID string
Manifest Manifest
// SourceURL is where the manifest came from (remote endpoint base).
SourceURL string
// Files returns an artifact file (entry, module, strings, schema) for
// the installed version, or false. Hosted runtimes load code through it.
Files func(path string) ([]byte, bool)
// Host is the per-plugin host-services handle (SPEC §5.1.5).
Host Host
}
Installed is the host's record of one installed plugin, handed to a RuntimeFactory when an instance is opened.
type IntegrationMeta ¶
type IntegrationMeta struct {
Category string `json:"category"`
Logo string `json:"logo,omitempty"`
Adds []string `json:"adds"` // 1..4 plain lines or $t: keys
Connect string `json:"connect"` // fields|device_code|none
Test bool `json:"test,omitempty"`
}
IntegrationMeta is mandatory for the integration kind.
type JournalEntry ¶
type JournalEntry struct {
ID int64 `json:"id"`
Plugin string `json:"plugin"`
Op string `json:"op"`
Detail string `json:"detail,omitempty"`
Inverse json.RawMessage `json:"inverse,omitempty"`
Shadow bool `json:"shadow"`
Undone bool `json:"undone"`
Created time.Time `json:"created"`
}
JournalEntry is one recorded write and its inverse.
type ListParamField ¶
type ListParamField struct {
Key string `json:"key"`
Name string `json:"name"`
Kind string `json:"kind"`
Label string `json:"label"`
Help string `json:"help"`
Hint string `json:"hint"`
Required bool `json:"required"`
Placeholder string `json:"placeholder"`
Default any `json:"default"`
Options []struct {
Value string `json:"value"`
Label string `json:"label"`
} `json:"options"`
}
func ParseListParamFields ¶
func ParseListParamFields(raw json.RawMessage) []ListParamField
type ListSourceMeta ¶
type ListSourceMeta struct {
Key string `json:"key"`
Label string `json:"label"`
Hint string `json:"hint,omitempty"`
Catalog string `json:"catalog"`
Params json.RawMessage `json:"params,omitempty"`
MaxItems int `json:"maxItems,omitempty"` // ≤ 2000
Refresh string `json:"refresh,omitempty"` // ≥ 1h
}
ListSourceMeta is one contributed list source.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager is the plugin host. It is safe for concurrent use.
func (*Manager) Addon ¶
Addon is the installed plugin as a Stremio add-on: its Stremio manifest read through Fetcher.
func (*Manager) AddonConfig ¶
AddonConfig describes an installed add-on's settings for the console.
func (*Manager) AddonConfigPage ¶
AddonConfigPage opens the configure page of an installed add-on.
func (*Manager) AddonFetch ¶
AddonFetch reads one Stremio route from the add-on behind plugin id: the add-on itself, or the link a Studio-edited version of it carries. It uses the same guarded, plain add-on transport as an imported add-on.
func (*Manager) AddonLink ¶
AddonLink returns the sealed add-on link behind a plugin, for carrying it to a Studio-built replacement or copy. Never send it to a client.
func (*Manager) AddonLinkConfigPage ¶
AddonLinkConfigPage opens the configure page for an add-on not yet installed, from its install link.
func (*Manager) ApplyUpdate ¶
ApplyUpdate installs a pending update previously stored by CheckUpdate.
func (*Manager) BrowseDirectory ¶
BrowseDirectory is the common owner discovery path. No network request is made during registry rendering or ordinary media browse. Disabling/removing a provider prevents both cached descriptors and direct API calls from use.
func (*Manager) Call ¶
Call makes one call to a plugin through its runtime, records it in the inspector ring (secrets redacted) and feeds failures into health. Adapters (WS9) call plugins only through here.
func (*Manager) CallStream ¶
func (m *Manager) CallStream(ctx context.Context, pluginID string, req Request) (Response, io.ReadCloser, error)
CallStream returns a streaming response. The call deadline remains active until the body is closed; callers must close it on every path.
func (*Manager) CheckHealth ¶
CheckHealth calls /ether/health once and updates the health record. A failing call feeds the failure policy through Call already; a plugin reporting attention or error is recorded without counting as a crash.
func (*Manager) CheckUpdate ¶
CheckUpdate fetches the plugin's source again. When a newer version exists it is stored as a pending update; auto-update applies it at once only for verified plugins whose permissions did not grow (SPEC §5.4).
func (*Manager) Configure ¶
func (m *Manager) Configure(ctx context.Context, id string, incoming map[string]any) (map[string]string, error)
Configure validates incoming settings against the schema, stores them (secrets sealed per plugin; a "Saved" value keeps the stored secret), then calls the plugin's /ether/configure and surfaces its field errors.
func (*Manager) DeliverOutbox ¶
DeliverOutbox sends queued events to one plugin in batches of 50 and deletes the ones it acks. A missing ack keeps events for redelivery (at least once).
func (*Manager) FetchPickedSubtitle ¶
func (m *Manager) FetchPickedSubtitle(ctx context.Context, plugin, title, subtitle, token, rawURL string) ([]byte, error)
FetchPickedSubtitle consumes the same one-shot authorization as a plugin download call. Every redirect is checked against the declared hosts.
func (*Manager) Fetcher ¶
func (m *Manager) Fetcher(plugin string) AddonFetcher
Fetcher returns the stremio.Fetcher for an installed plugin.
func (*Manager) GetSettings ¶
func (m *Manager) GetSettings(ctx context.Context, id string) (map[string]any, json.RawMessage, error)
GetSettings returns settings with secrets replaced by "Saved".
func (*Manager) Handler ¶
Handler serves the owner API. It is mounted at /api/plugins by the app, behind owner auth; paths here are relative to that mount.
func (*Manager) Hot ¶
Hot returns the hosted runtime of an enabled plugin when it exports the hot-path ABI, loading it if needed. It may block on a load, so it is for background work (replay, Studio); the play path uses HotReady.
func (*Manager) HotReady ¶
func (m *Manager) HotReady(pluginID string) (HotRuntime, bool)
HotReady is the play-path accessor. It never blocks: it returns the plugin's hosted runtime only when it is already loaded, and otherwise starts loading it in the background and reports false, so the caller treats the plugin's steps and conditions as neutral for this resolve. Plugins in shadow mode are never ready on the play path. Runtimes are dropped on update, disable, remove and failure (closeRuntime) and warmed again when descriptors sync.
func (*Manager) InstallAddon ¶
InstallAddon installs the add-on at link, or finds it when that link is already installed, and switches the requested roles on. A private host is trusted as LAN: the owner pasted it.
func (*Manager) Journal ¶
func (m *Manager) Journal(ctx context.Context, id string, limit int, shadowOnly bool) ([]JournalEntry, error)
Journal returns a plugin's journal (liveOnly: applied and not undone; shadowOnly is handled by the caller through Journal).
func (*Manager) MintSubtitlePick ¶
MintSubtitlePick is called only after a viewer selects a listed subtitle.
func (*Manager) MintSubtitleURLPick ¶
MintSubtitleURLPick binds a user's selection to the exact URL returned by a Stremio subtitle search. A foreign manifest grants no arbitrary host access.
func (*Manager) OnSync ¶
OnSync registers a callback notified whenever a plugin's enabled state or manifest changes (install, update, rollback, enable, disable, auto-disable, or remove). Any already-installed plugins are synced immediately.
func (*Manager) PackageFiles ¶
PackageFiles returns an installed plugin's own files for its current version, so Studio can open it for editing.
func (*Manager) PluginSettings ¶
PluginSettings returns a plugin's stored settings with its own secrets, for delivery to that plugin only (remote sidecars read it from the authenticated plugin-host API after a restart or reconnect).
func (*Manager) PreviewCatalogGet ¶
func (*Manager) PreviewCatalogSearch ¶
func (m *Manager) PreviewCatalogSearch(ctx context.Context, query string, limit, offset int) (json.RawMessage, bool, error)
PreviewCatalogSearch and PreviewCatalogGet give a draft read access to the real catalogue, the way catalog: read does once installed. ok is false when the server has no catalogue backend (tests, early startup).
func (*Manager) PreviewFetch ¶
func (m *Manager) PreviewFetch(ctx context.Context, network []string, req FetchRequest) (FetchResponse, error)
PreviewFetch performs a draft plugin's http.fetch for Studio's preview: the same SSRF-guarded client and host allowlist as an installed plugin, checked against the draft's own declared network permissions, so a preview shows the real data the plugin will see once installed.
func (*Manager) PreviewInstall ¶
PreviewInstall fetches and validates a source without installing it.
func (*Manager) Publish ¶
Publish normalizes and fans out one Ether event: it is written to the 7-day event log and queued for every enabled plugin that subscribed to it (and was not revoked). Viewer identity is stripped per plugin unless the plugin's grants allow it.
func (*Manager) RecordFailure ¶
RecordFailure reports an adapter-observed failure (such as an HTTP 5xx or malformed payload) into the plugin's health record and failure policy.
func (*Manager) RecordRanking ¶
func (m *Manager) RecordRanking(ctx context.Context, pluginID string, r RankingReport)
RecordRanking records a resolve's hot-path outcome for one plugin. A ranking step left out for running past its budget flags the plugin for the owner until one of its rankings finishes in time again; the periodic health check does not clear it, since the plugin's own health answer says nothing about its ranking. A resolve where the plugin kept to time and was not being skipped writes nothing. Safe for concurrent use; the ranking adapters call it when a resolve ends.
func (*Manager) RecordSlow ¶
RecordSlow adds n slow calls or slow hot-path candidates to a plugin's health and flags it for the owner's attention. It is safe for concurrent use; the ranking adapters call it after a resolve.
func (*Manager) RegisterRuntime ¶
func (m *Manager) RegisterRuntime(kind string, f RuntimeFactory)
RegisterRuntime adds a runtime factory for a runtime kind ("hosted" or "remote"). WS8 calls it at wiring time. Safe to call after Start.
func (*Manager) RelayHandler ¶
RelayHandler serves /api/addon-relay/{token}/{path...} without the console's sign-in: the token is the permission.
func (*Manager) Remove ¶
Remove uninstalls a plugin: it offers undo first (when undoFirst, every live journal inverse is replayed), then purges KV, secrets, grants, artifacts, logs and its registry entries.
func (*Manager) ResolveText ¶
ResolveText looks up key in the plugin's strings for locale, then en.
func (*Manager) Revoke ¶
Revoke disables an installed plugin that was marked revoked in the signed catalogue, records the reason in its health, and posts a console notice (SPEC WS12, §10). It returns true when an installed plugin was newly disabled or updated with the revocation reason.
func (*Manager) Run ¶
Run drives health checks, scheduled jobs and outbox delivery until ctx ends. Leader plugins run jobs and event delivery only on the leader; every_node plugins run everywhere. Health checks run on every node.
func (*Manager) SaveAddonConfig ¶
func (m *Manager) SaveAddonConfig(ctx context.Context, id string, ch AddonConfigChange) (Record, error)
SaveAddonConfig applies new settings in place: the plugin keeps its id, roles, pins and collections; only its sealed link and manifest change.
func (*Manager) SetCatalogue ¶
SetCatalogue attaches the signed plugin catalogue (WS12).
func (*Manager) SetEnabled ¶
SetEnabled enables or disables a plugin and refreshes its descriptors.
func (*Manager) SetGrants ¶
SetGrants replaces one plugin's grants. Host calls re-check grants on every call, so a revoke applies mid-call.
func (*Manager) SetRoles ¶
SetRoles switches an installed add-on's roles on or off: off lists the capabilities it should stop playing (its catalogs, streams, subtitles, Live TV channels…). Only roles its manifest offers can be named.
func (*Manager) SettingsSchema ¶
SettingsSchema returns the resolved settings schema for a plugin.
func (*Manager) Start ¶
Start re-registers descriptors and subscribes to cluster invalidations. Run starts the health, scheduler and outbox loops.
func (*Manager) StremioResource ¶
func (m *Manager) StremioResource(ctx context.Context, plugin, resource, typ, id string, extra map[string]string) (Response, error)
StremioResource calls declared read-only resources through the same guarded, metered runtime used by native adapters. It never treats registration as a call.
func (*Manager) SubscribeInvalidations ¶
func (m *Manager) SubscribeInvalidations() func()
SubscribeInvalidations re-syncs descriptors when another node changes a plugin. Returns an unsubscribe function (nil bus: no-op).
func (*Manager) TestAddonConfig ¶
func (m *Manager) TestAddonConfig(ctx context.Context, id string, ch AddonConfigChange) (AddonConfigResult, error)
TestAddonConfig loads the add-on with the new settings without saving.
func (*Manager) TextResolver ¶
func (m *Manager) TextResolver() extend.TextResolver
TextResolver resolves a plugin string for a locale, falling back to en.
type Manifest ¶
type Manifest struct {
ID string `json:"id"`
Version string `json:"version"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Logo string `json:"logo,omitempty"`
Background string `json:"background,omitempty"`
Types []string `json:"types,omitempty"`
AddonCatalogs []StremioCat `json:"addonCatalogs,omitempty"`
Catalogs []StremioCat `json:"catalogs,omitempty"`
Resources stremio.Resources `json:"resources,omitempty"`
IDPrefixes []string `json:"idPrefixes,omitempty"`
BehaviorHints stremio.BehaviorHints `json:"behaviorHints,omitzero"`
Ether *EtherBlock `json:"ether,omitempty"`
// contains filtered or unexported fields
}
Manifest is a plugin's manifest.json: the Stremio manifest fields, typed by the one Stremio model (internal/stremio), plus Ether's fields under Ether (SPEC §5.1.1). A manifest with a nil Ether is a plain Stremio add-on. Every Stremio rule (resources, ids, catalogs, extras) is the library's, reached through Stremio().
func ParseManifest ¶
ParseManifest decodes manifest JSON. Unknown fields are ignored (SPEC §5.1.1). Call Validate before trusting the result.
func (Manifest) AcceptsResource ¶
AcceptsResource reports whether the add-on serves resource for typ and id (internal/stremio.Manifest.TakesID).
func (Manifest) AddonRoles ¶
func (m Manifest) AddonRoles() []Capability
AddonRoles are the roles a plain Stremio add-on can play, derived from its manifest, whether or not the owner switched them off.
func (Manifest) CatalogsOfType ¶
func (m Manifest) CatalogsOfType(typ string) []StremioCat
CatalogsOfType returns the catalogs of one content type.
func (Manifest) ConfigurationRequired ¶
ConfigurationRequired reports an add-on installed from its unconfigured link.
func (Manifest) EffectiveEther ¶
func (m Manifest) EffectiveEther() *EtherBlock
EffectiveEther describes native adapters without modifying the foreign manifest stored on disk or inventing permissions for a third-party add-on.
func (Manifest) HasCapability ¶
func (m Manifest) HasCapability(c Capability) bool
HasCapability reports whether the manifest declares c.
func (Manifest) HasResource ¶
HasResource reports whether the manifest declares the named resource.
func (Manifest) IsStremioOnly ¶
IsStremioOnly reports whether m is a plain Stremio add-on (no ether block).
func (Manifest) RuntimeKind ¶
RuntimeKind is the runtime that serves the plugin. A plain Stremio add-on (no ether block) is always reached over HTTP: "remote".
func (Manifest) ServesTV ¶
ServesTV reports whether a plain Stremio add-on is a Live TV source: it lists `tv` catalogs and answers `tv` streams.
func (Manifest) SpeaksStremio ¶
SpeaksStremio reports whether Ether reads this plugin's catalogues, metadata, subtitles, channels and directories over Stremio routes: a plain add-on, or a native plugin built from one in Studio.
func (*Manifest) UnmarshalJSON ¶
UnmarshalJSON completes a Stremio-backed plugin's roles from its catalogs and resources wherever a manifest is read: packages, stored records and drafts alike.
type MarkersMeta ¶
type MarkersMeta struct {
Kinds []string `json:"kinds"` // intro|credits|recap|preview
}
MarkersMeta is mandatory for markers.
type MetadataMeta ¶
type MetadataMeta struct {
Types []string `json:"types"`
}
MetadataMeta declares a provider of canonical catalogue records. Resolution happens during explicit materialization, never as part of ordinary browsing. Ether-native providers implement POST /ether/metadata/resolve using core.MetadataRequest and a {"title": core.Title} response.
type NotificationMeta ¶
type NotificationMeta struct {
Fields json.RawMessage `json:"fields,omitempty"`
SendTest bool `json:"sendTest"`
Formats []string `json:"formats,omitempty"`
MaxLength int `json:"maxLength,omitempty"`
}
NotificationMeta is mandatory for notify.
type PageMeta ¶
type PageMeta struct {
Key string `json:"key"`
Label string `json:"label"`
Route string `json:"route"` // plugin route returning {spec,data}
Group string `json:"group,omitempty"`
Icon string `json:"icon,omitempty"`
}
PageMeta is one contributed console page (ViewSpec, SPEC §5.6).
type PermissionIncreaseError ¶
type PermissionIncreaseError struct{ Added []string }
PermissionIncreaseError reports an update that asks for more access.
func (*PermissionIncreaseError) Error ¶
func (e *PermissionIncreaseError) Error() string
type Permissions ¶
type Permissions struct {
Network []string `json:"network,omitempty" yaml:"network,omitempty"`
Catalog string `json:"catalog,omitempty" yaml:"catalog,omitempty"` // ""|none|read
Viewers ViewerPerms `json:"viewers,omitempty" yaml:"viewers,omitempty"`
Collections string `json:"collections,omitempty" yaml:"collections,omitempty"` // ""|none|write
Folders string `json:"folders,omitempty" yaml:"folders,omitempty"` // ""|none|read
Secrets []string `json:"secrets,omitempty" yaml:"secrets,omitempty"`
}
Permissions is what a plugin asks for; anything not declared is denied (SPEC §5.4). Empty means none.
type Preview ¶
type Preview struct {
Manifest Manifest `json:"manifest"`
PermissionLines []string `json:"permissions"`
NeedsViewers bool `json:"needsViewers"`
NeedsFolders bool `json:"needsFolders"`
Verified bool `json:"verified"`
StremioOnly bool `json:"stremioOnly"`
AlreadyInstalled bool `json:"alreadyInstalled,omitempty"`
InstalledVersion string `json:"installedVersion,omitempty"`
AddedPermissions []string `json:"addedPermissions,omitempty"`
// contains filtered or unexported fields
}
Preview is what the install sheet shows before the owner confirms.
type RankingReport ¶
type RankingReport struct {
// Slow counts candidates and conditions that went neutral on budget.
Slow int
// Skipped counts ranking steps left out because the plugin ran past
// its time budget; Ranked counts ranking steps that finished in time.
Skipped, Ranked int
}
RankingReport is what one resolve saw of a plugin on the hot path.
type RankingStepMeta ¶
type RankingStepMeta struct {
Key string `json:"key"`
Label string `json:"label"`
Hint string `json:"hint,omitempty"`
Editor json.RawMessage `json:"editor,omitempty"`
DefaultPosition int `json:"defaultPosition,omitempty"`
Budget json.RawMessage `json:"budget,omitempty"`
}
RankingStepMeta is one contributed ranking step (hosted only).
type Record ¶
type Record struct {
ID string
Name string
Version string
Kind string
Manifest Manifest
ManifestRaw json.RawMessage
SourceKind string // url|github|pkg|studio|catalogue
SourceURL string
Enabled bool
Verified bool
Shadow bool
AutoUpdate bool
UpdateVersion string
PrevVersion string
InstalledAt time.Time
UpdatedAt time.Time
// RolesOff are the capabilities the owner switched off (a Stremio
// add-on's catalogs, streams, subtitles…). Manifest already reflects
// them: EffectiveEther leaves them out.
RolesOff []Capability
// contains filtered or unexported fields
}
Record is one installed plugin as stored.
type Request ¶
type Request struct {
PluginID string `json:"pluginId"`
Method string `json:"method"`
Path string `json:"path"`
Query map[string]string `json:"query,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Body json.RawMessage `json:"body,omitempty"`
// Locale is the console locale for calls that return copy.
Locale string `json:"locale,omitempty"`
}
Request is one HTTP-shaped call from Ether to a plugin (SPEC §5.1.2). Hosted plugins receive the same object in-process.
type Response ¶
type Response struct {
Status int `json:"status"`
Headers map[string]string `json:"headers,omitempty"`
Body json.RawMessage `json:"body,omitempty"`
}
Response is a plugin's answer to a Request.
type RoleState ¶
type RoleState struct {
Role Capability `json:"role"`
On bool `json:"on"`
}
RoleState is one role of an add-on for the console.
type RuleConditionMeta ¶
type RuleConditionMeta struct {
Key string `json:"key"`
Label string `json:"label"`
Operators []string `json:"operators,omitempty"`
Editor json.RawMessage `json:"editor,omitempty"`
}
RuleConditionMeta is one contributed rule condition (hosted only).
type Runtime ¶
Runtime is how the host reaches one installed plugin. WS8a (hosted) and WS8b (remote) implement it; tests use a fake. Call must honour ctx deadlines. Close releases the instance; the host may open a fresh one after a failure (restart with backoff).
type RuntimeDecl ¶
type RuntimeDecl struct {
Kind string `json:"kind"` // "hosted" or "remote"
Entry string `json:"entry,omitempty"`
Module string `json:"module,omitempty"`
}
RuntimeDecl declares how a plugin runs: hosted (Entry JS or Module WASM) or remote (the manifest URL or a tunnel is the endpoint).
type RuntimeFactory ¶
RuntimeFactory opens a Runtime for one installed plugin. The factory is chosen by manifest ether.runtime.kind ("hosted" or "remote").
func HostedRuntimeFactory ¶
func HostedRuntimeFactory(eng *wasm.Engine) RuntimeFactory
HostedRuntimeFactory opens hosted plugins (runtime.kind "hosted") on the wazero engine: JavaScript and TypeScript entries run on QuickJS, raw modules through the documented WASM ABI.
type ScheduleEntry ¶
ScheduleEntry is one pull job Ether runs (minimum interval 15m).
type SlotMeta ¶
type SlotMeta struct {
Slot string `json:"slot"` // title.panel|viewer.tab|dashboard.panel|actionMenu.*
Key string `json:"key"`
Label string `json:"label"`
Route string `json:"route,omitempty"`
Action string `json:"action,omitempty"`
}
SlotMeta is one contributed console slot.
type Source ¶
type Source struct {
Kind string // url|github|pkg|studio|catalogue
URL string
// ID and Version select an entry from the signed catalogue (kind "catalogue").
ID string
Version string
// SHA256 is the expected lowercase hex SHA-256 of the downloaded artifact.
SHA256 string
// Pkg is the .etherpkg bytes (kind "pkg") or a Studio package.
Pkg []byte
// Manifest and Files install directly (Studio with loose files).
Manifest json.RawMessage
Files map[string][]byte
// Verified is set only by the signed catalogue (WS12).
Verified bool
// LAN allows a private-network manifest URL (owner confirmed).
LAN bool
// contains filtered or unexported fields
}
Source describes where an install comes from.
type SourceMeta ¶
type SourceMeta struct {
Class string `json:"class"` // debrid|usenet|indexer|direct
Abilities []string `json:"abilities,omitempty"`
Limits json.RawMessage `json:"limits,omitempty"`
}
SourceMeta is mandatory for stream_source.
type StremioExtra ¶
StremioExtra is one catalog extra declaration.
type SubtitlesMeta ¶
type SubtitlesMeta struct {
Languages json.RawMessage `json:"languages,omitempty"`
Formats []string `json:"formats,omitempty"`
}
SubtitlesMeta is mandatory for subtitles. Languages is "any" or a list.
type Summary ¶
type Summary struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Kind string `json:"kind,omitempty"`
Summary string `json:"summary,omitempty"`
Icon string `json:"icon,omitempty"`
Enabled bool `json:"enabled"`
Verified bool `json:"verified"`
Shadow bool `json:"shadow"`
AutoUpdate bool `json:"autoUpdate"`
UpdateVersion string `json:"updateVersion,omitempty"`
PrevVersion string `json:"prevVersion,omitempty"`
Health string `json:"health"`
// HealthReason is the plain-language reason behind a non-ok health,
// such as "Recent calls were slow."
HealthReason string `json:"healthReason,omitempty"`
Capabilities []string `json:"capabilities,omitempty"`
SourceKind string `json:"sourceKind,omitempty"`
StremioOnly bool `json:"stremioOnly,omitempty"`
InstalledAt int64 `json:"installedAt"`
// Roles and Host describe a Stremio add-on: what it can do, which of
// that is switched on, and the host it is reached at (never the link,
// which carries the owner's configuration).
Roles []RoleState `json:"roles,omitempty"`
Host string `json:"host,omitempty"`
}
Summary is one row of the installed list.
type TestResult ¶
type TestResult struct {
OK bool `json:"ok"`
Message string `json:"message,omitempty"`
Details []string `json:"details,omitempty"`
}
TestResult is the plugin's /ether/test answer.
type ToolMeta ¶
type ToolMeta struct {
Name string `json:"name"`
Title string `json:"title"`
Description string `json:"description"`
InputSchema json.RawMessage `json:"inputSchema"`
ReadOnly bool `json:"readOnly,omitempty"`
Destructive bool `json:"destructive,omitempty"`
OpenWorld bool `json:"openWorld,omitempty"`
}
ToolMeta is one contributed agent tool.
type ValidationError ¶
type ValidationError struct{ Fields []FieldError }
ValidationError carries every field problem found at once.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
type ViewerPerms ¶
type ViewerPerms struct {
Identity string `json:"identity,omitempty" yaml:"identity,omitempty"` // none|granted_viewers|all
WatchHistory string `json:"watch_history,omitempty" yaml:"watch_history,omitempty"` // none|granted_viewers|all
WriteWatchState string `json:"write_watch_state,omitempty" yaml:"write_watch_state,omitempty"` // none|granted_viewers
}
ViewerPerms holds the three viewer permission levels.
Source Files
¶
- addon_bridge.go
- addon_form.go
- addon_relay.go
- addonconfig.go
- addons.go
- collection_context.go
- contract.go
- descriptors.go
- directory.go
- events.go
- host.go
- hosted.go
- http.go
- install.go
- list_params.go
- manager.go
- manifest.go
- notify_adapter.go
- preview_host.go
- proposals.go
- settings_public.go
- store.go
- stremio_manifest.go
- stremio_resource.go
- subtitle_pick.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package adapters bridges runtime plugin contributions (WS9a list sources and WS9c Live TV channel sources) into Ether's collection, personalization and Live TV registries.
|
Package adapters bridges runtime plugin contributions (WS9a list sources and WS9c Live TV channel sources) into Ether's collection, personalization and Live TV registries. |
|
Package kit implements Ether's plugin conformance kit and copy linter (SPEC §5.1–§5.6, WS11g), shared across install previews, Studio, the `ether plugin` CLI, and catalogue CI.
|
Package kit implements Ether's plugin conformance kit and copy linter (SPEC §5.1–§5.6, WS11g), shared across install previews, Studio, the `ether plugin` CLI, and catalogue CI. |
|
Package remote is the remote plugin runtime (SPEC §5.3, WS8b).
|
Package remote is the remote plugin runtime (SPEC §5.3, WS8b). |
|
Package studio provides the plugin Studio replay runner (WS11c) and the Studio and extensibility MCP and agent tools (WS11h).
|
Package studio provides the plugin Studio replay runner (WS11c) and the Studio and extensibility MCP and agent tools (WS11h). |
|
Package wasm is Ether's hosted plugin runtime: it runs plugin code inside the Ether process, sandboxed, with no ports and no operating-system access.
|
Package wasm is Ether's hosted plugin runtime: it runs plugin code inside the Ether process, sandboxed, with no ports and no operating-system access. |