Extensions run as independent processes and talk to the AList v4 host over a gRPC channel built with hashicorp/go-plugin. This repository provides the plugin side of that contract: the interfaces, the runtime, and the wire protocol.
- Full Kind coverage — contracts for
StorageDriver,AuthNMethod,SearchIndexer,OfflineDownloadTool,ArchiveTool,EventHook,ScheduledJob,BackgroundService,APIRoute,AccessProtocol,FileDecorator,Notification, and more - Assist — an auxiliary interface any Kind's implementation can additionally satisfy; the SDK mounts it alongside the primary Kind in the same process (
grpcplugin.ServeMulti) and guaranteesInitruns at most once per process even when dispensed under more than one name - Optional capabilities —
Copier,Putter,RapidPutter(rapid/instant upload viaCapPutRapid) and similar interfaces a driver can implement to opt into richer host behavior - Public routing —
Contributions.PublicPrefixrequests a short, top-level URL prefix for an extension's public pages - One-line runtime — implement an interface and call
grpcplugin.Serve(orgrpcplugin.ServeMultifor several Kinds/instances in one process) - Stable wire protocol —
grpcprotois generated with buf, so host and plugin evolve independently - Typed errors across the boundary —
ErrCodecarries sentinel errors (NotImplement,PermissionDenied,ArchiveIsDir,ArchiveInvalid, …) through the gRPC round trip intact
Thumbnailer— dispatch exists only for a trusted, in-process instance the host registers itself; there is no gRPC leg. A plugin declaring this Kind is refused at install.FileTransformer,MetadataProvider— reserved identifiers with no implementation on either side. A plugin declaring either is refused at install.Previewer,UIPanel— accepted at install but inert as aKind. A custom previewer or panel is contributed throughContributions.Previewers/Contributions.UIPanels, not by declaring these Kinds in a manifest.
v0.2.0: OfflineDownloadTool.Status returns ToolStatus, whose Err field changed type from error to string (empty string means no error — error can't cross the process boundary). If your plugin implements OfflineDownloadTool, change any ToolStatus.Err assignment or read from error to a plain string before upgrading past v0.1.0. Nothing else changed; pin to v0.1.0 if you need more time.
go get github.com/AlistGo/alist-ext@latestMinimal storage driver plugin:
package main
import (
ext "github.com/AlistGo/alist-ext"
"github.com/AlistGo/alist-ext/grpcplugin"
)
func main() {
grpcplugin.Serve(myDriver{}) // myDriver implements ext.StorageDriver
}Scaffolding, signing, and packing are hidden subcommands of the AList host binary:
alist plugin new --id com.example.mydriver # generate a plugin project skeleton
alist plugin sign --key key.hex --dir ./dist # sign a built package directory
alist plugin pack --dir ./dist --out out.tar.gz| Package | Description |
|---|---|
ext |
Extension contracts: Manifest, Extension, Assist, the per-Kind interfaces, and optional capability interfaces |
ext/grpcplugin |
Plugin-side runtime — implement a contract, call grpcplugin.Serve to run it as a plugin process |
ext/grpcproto |
gRPC wire contract (buf-generated) and codec used between host and plugin |
Errors crossing the host/plugin boundary carry an explicit ErrCode, so errors.Is-style control flow keeps working after a gRPC round trip:
if code, ok := ext.CodeOf(err); ok && code == ext.ErrCodeObjectNotFound {
// handle missing object
}This repository is a release snapshot of the ext/ directory in the AlistGo/alist v4 monorepo. Development happens there; each tag here mirrors a point in that history. Plugin projects should depend on a tag of this repository, not the ext/ path in the main repo.
Issues and pull requests for the SDK itself go to AlistGo/alist, where ext/ development happens.
MIT — see LICENSE.