- RegistryAPIPath, RegistryPlugin, RegistryPluginDetail, RegistryVersion, envelopes, errors, ingest types - ValidVersion, CompareVersions, BaseVersion, Satisfies, NewestCompatible - docs: Registry API v1 reference in plugins/marketplace.md
134 lines
4.2 KiB
Go
134 lines
4.2 KiB
Go
package kiosk
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
)
|
|
|
|
// The registry API v1 contract. The summercms.io registry encodes its
|
|
// responses with these types and the summer tool and the admin decode
|
|
// them, so no other copy of the shape exists. Rules: every response is an
|
|
// envelope object (data, meta or error); clients ignore unknown fields;
|
|
// changes within v1 are additive only. The API is GET-only for clients,
|
|
// needs no credentials and answers with open CORS and
|
|
// Cache-Control: public, max-age=300 plus an ETag.
|
|
|
|
// RegistryAPIPath is the base path of the registry API v1:
|
|
//
|
|
// GET {base}/plugins?q=&category= ListResponse
|
|
// GET {base}/plugins/{id} DetailResponse
|
|
// GET {base}/plugins/{id}/versions VersionsResponse, newest first
|
|
// POST {base}/ingest IngestRequest -> 202 IngestResponse (authenticated)
|
|
//
|
|
// Errors answer with an ErrorResponse: 404 not_found, 400 invalid_query.
|
|
const RegistryAPIPath = "/api/registry/v1"
|
|
|
|
// Error codes of a RegistryError.
|
|
const (
|
|
// RegistryErrorNotFound is the code of a 404: no such plugin.
|
|
RegistryErrorNotFound = "not_found"
|
|
// RegistryErrorInvalidQuery is the code of a 400: a bad query parameter.
|
|
RegistryErrorInvalidQuery = "invalid_query"
|
|
)
|
|
|
|
// RegistryPlugin is one plugin in the registry list.
|
|
type RegistryPlugin struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Module string `json:"module"`
|
|
Package string `json:"package"`
|
|
Repository string `json:"repository"`
|
|
Category string `json:"category"`
|
|
Featured bool `json:"featured"`
|
|
IconURL string `json:"icon_url"`
|
|
LatestVersion string `json:"latest_version"`
|
|
LatestFramework string `json:"latest_framework"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// RegistryPluginDetail is one plugin with its README, screenshots and the
|
|
// requirements of its latest version.
|
|
type RegistryPluginDetail struct {
|
|
RegistryPlugin
|
|
ReadmeMarkdown string `json:"readme_markdown"`
|
|
ReadmeHTML string `json:"readme_html"`
|
|
Screenshots []RegistryScreenshot `json:"screenshots"`
|
|
Requires Requires `json:"requires"`
|
|
}
|
|
|
|
// RegistryScreenshot is one screenshot of a plugin listing.
|
|
type RegistryScreenshot struct {
|
|
URL string `json:"url"`
|
|
Caption string `json:"caption"`
|
|
}
|
|
|
|
// RegistryVersion is one tagged release of a plugin, with the minimums
|
|
// its plugin.yaml declared at that tag.
|
|
type RegistryVersion struct {
|
|
Version string `json:"version"`
|
|
Framework string `json:"framework"`
|
|
Requires Requires `json:"requires"`
|
|
Module string `json:"module"`
|
|
Package string `json:"package"`
|
|
Commit string `json:"commit"`
|
|
TaggedAt time.Time `json:"tagged_at"`
|
|
}
|
|
|
|
// ListResponse answers GET {base}/plugins.
|
|
type ListResponse struct {
|
|
Data []RegistryPlugin `json:"data"`
|
|
Meta ListMeta `json:"meta"`
|
|
}
|
|
|
|
// ListMeta carries the number of plugins that matched.
|
|
type ListMeta struct {
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
// DetailResponse answers GET {base}/plugins/{id}.
|
|
type DetailResponse struct {
|
|
Data RegistryPluginDetail `json:"data"`
|
|
}
|
|
|
|
// VersionsResponse answers GET {base}/plugins/{id}/versions, newest first.
|
|
type VersionsResponse struct {
|
|
Data []RegistryVersion `json:"data"`
|
|
}
|
|
|
|
// ErrorResponse is the body of every registry error.
|
|
type ErrorResponse struct {
|
|
Error RegistryError `json:"error"`
|
|
}
|
|
|
|
// RegistryError is a stable code and a human-readable message.
|
|
type RegistryError struct {
|
|
Code string `json:"code"`
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// IngestRequest is the body of POST {base}/ingest.
|
|
type IngestRequest struct {
|
|
Repository string `json:"repository"`
|
|
}
|
|
|
|
// IngestResponse answers an accepted ingest request (202).
|
|
type IngestResponse struct {
|
|
Data IngestResult `json:"data"`
|
|
}
|
|
|
|
// IngestResult names the repository queued for ingestion.
|
|
type IngestResult struct {
|
|
Repository string `json:"repository"`
|
|
Queued bool `json:"queued"`
|
|
}
|
|
|
|
// MarshalJSON encodes the map as an object, {} when it is empty, so the
|
|
// registry never sends null for requires.
|
|
func (r Requires) MarshalJSON() ([]byte, error) {
|
|
if r == nil {
|
|
return []byte("{}"), nil
|
|
}
|
|
return json.Marshal(map[string]string(r))
|
|
}
|