refactor(plugins): remove non-functional experimental manifest option (#5821)

The `experimental.threads` manifest option never actually worked, so drop
it from the schema, the generated types, the loader and the docs.
This commit is contained in:
Deluan Quintão 2026-07-19 18:52:30 -04:00 committed by GitHub
parent fed9665060
commit bf79d2f3a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1 additions and 141 deletions

View File

@ -136,7 +136,7 @@ Every plugin must include a `manifest.json` file. Example:
**Required fields:** `name`, `author`, `version`
**Optional fields:** `description`, `website`, `config`, `permissions`, `experimental`
**Optional fields:** `description`, `website`, `config`, `permissions`
#### Config Definition
@ -160,24 +160,6 @@ The `config` field defines the plugin's configuration schema using [JSON Schema
}
```
#### Experimental Features
Plugins can opt-in to experimental WebAssembly features that may change or be removed in future versions. Currently supported:
- **`threads`** Enables WebAssembly threads support (for plugins compiled with multi-threading)
```json
{
"experimental": {
"threads": {
"reason": "Required for concurrent audio processing"
}
}
}
```
> **Note:** Experimental features may have compatibility or performance implications. Use only when necessary.
---
## Capabilities

View File

@ -13,8 +13,6 @@ import (
"github.com/navidrome/navidrome/plugins/host"
"github.com/navidrome/navidrome/scheduler"
"github.com/tetratelabs/wazero"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/experimental"
"golang.org/x/sync/errgroup"
)
@ -377,12 +375,6 @@ func (m *Manager) loadPluginWithConfig(p *model.Plugin) error {
WithCompilationCache(m.cache).
WithCloseOnContextDone(true)
// Enable experimental threads if requested in manifest
if pkg.Manifest.HasExperimentalThreads() {
runtimeConfig = runtimeConfig.WithCoreFeatures(api.CoreFeaturesV2 | experimental.CoreFeaturesThreads)
log.Debug(ctx, "Enabling experimental threads support")
}
extismConfig := extism.PluginConfig{
EnableWasi: true,
RuntimeConfig: runtimeConfig,

View File

@ -34,9 +34,6 @@
"permissions": {
"$ref": "#/$defs/Permissions"
},
"experimental": {
"$ref": "#/$defs/Experimental"
},
"config": {
"$ref": "#/$defs/ConfigDefinition"
}
@ -58,27 +55,6 @@
}
}
},
"Experimental": {
"type": "object",
"description": "Experimental features that may change or be removed in future versions",
"additionalProperties": false,
"properties": {
"threads": {
"$ref": "#/$defs/ThreadsFeature"
}
}
},
"ThreadsFeature": {
"type": "object",
"description": "Enable experimental WebAssembly threads support",
"additionalProperties": false,
"properties": {
"reason": {
"type": "string",
"description": "Explanation for why threads support is needed"
}
}
},
"Permissions": {
"type": "object",
"description": "Permissions required by the plugin",

View File

@ -117,11 +117,6 @@ func ValidateWithCapabilities(m *Manifest, capabilities []Capability) error {
return nil
}
// HasExperimentalThreads returns true if the manifest requests experimental threads support.
func (m *Manifest) HasExperimentalThreads() bool {
return m.Experimental != nil && m.Experimental.Threads != nil
}
// HasLibraryFilesystemPermission checks if the manifest grants filesystem permission for libraries.
func (m *Manifest) HasLibraryFilesystemPermission() bool {
return m.Permissions != nil &&

View File

@ -45,12 +45,6 @@ func (j *ConfigDefinition) UnmarshalJSON(value []byte) error {
return nil
}
// Experimental features that may change or be removed in future versions
type Experimental struct {
// Threads corresponds to the JSON schema field "threads".
Threads *ThreadsFeature `json:"threads,omitempty" yaml:"threads,omitempty" mapstructure:"threads,omitempty"`
}
// HTTP access permissions for a plugin
type HTTPPermission struct {
// Explanation for why HTTP access is needed
@ -109,9 +103,6 @@ type Manifest struct {
// A brief description of what the plugin does
Description *string `json:"description,omitempty" yaml:"description,omitempty" mapstructure:"description,omitempty"`
// Experimental corresponds to the JSON schema field "experimental".
Experimental *Experimental `json:"experimental,omitempty" yaml:"experimental,omitempty" mapstructure:"experimental,omitempty"`
// The display name of the plugin
Name string `json:"name" yaml:"name" mapstructure:"name"`
@ -242,12 +233,6 @@ func (j *TaskQueuePermission) UnmarshalJSON(value []byte) error {
return nil
}
// Enable experimental WebAssembly threads support
type ThreadsFeature struct {
// Explanation for why threads support is needed
Reason *string `json:"reason,omitempty" yaml:"reason,omitempty" mapstructure:"reason,omitempty"`
}
// Users service permissions for accessing user information
type UsersPermission struct {
// Explanation for why users access is needed

View File

@ -117,76 +117,6 @@ var _ = Describe("Manifest", func() {
})
})
Describe("HasExperimentalThreads", func() {
It("returns false when no experimental section", func() {
m := &Manifest{}
Expect(m.HasExperimentalThreads()).To(BeFalse())
})
It("returns false when experimental section has no threads", func() {
m := &Manifest{
Experimental: &Experimental{},
}
Expect(m.HasExperimentalThreads()).To(BeFalse())
})
It("returns true when threads feature is present", func() {
m := &Manifest{
Experimental: &Experimental{
Threads: &ThreadsFeature{},
},
}
Expect(m.HasExperimentalThreads()).To(BeTrue())
})
It("returns true when threads feature has a reason", func() {
m := &Manifest{
Experimental: &Experimental{
Threads: &ThreadsFeature{
Reason: new("Required for concurrent processing"),
},
},
}
Expect(m.HasExperimentalThreads()).To(BeTrue())
})
It("parses experimental.threads from JSON", func() {
data := []byte(`{
"name": "Threaded Plugin",
"author": "Test Author",
"version": "1.0.0",
"experimental": {
"threads": {
"reason": "To use multi-threaded WASM module"
}
}
}`)
var m Manifest
err := json.Unmarshal(data, &m)
Expect(err).ToNot(HaveOccurred())
Expect(m.HasExperimentalThreads()).To(BeTrue())
Expect(m.Experimental.Threads.Reason).ToNot(BeNil())
Expect(*m.Experimental.Threads.Reason).To(Equal("To use multi-threaded WASM module"))
})
It("parses experimental.threads without reason from JSON", func() {
data := []byte(`{
"name": "Threaded Plugin",
"author": "Test Author",
"version": "1.0.0",
"experimental": {
"threads": {}
}
}`)
var m Manifest
err := json.Unmarshal(data, &m)
Expect(err).ToNot(HaveOccurred())
Expect(m.HasExperimentalThreads()).To(BeTrue())
})
})
Describe("ParseManifest", func() {
It("parses a valid manifest with users permission", func() {
data := []byte(`{