Improve golang type documentation and examples (#631)
Enhanced Go struct tags throughout `pkg/api/v0/types.go` and `pkg/model/types.go` to better align with the OpenAPI specification. ## Changes - Added comprehensive `doc` tags with detailed field descriptions matching OpenAPI - Added `example` tags showing valid values for fields (e.g., `"io.github.user/weather"`, `"npx"`) - Added `format` tags (`uri`, `date-time`) for better type specification - Added `pattern` and `enum` tags for validation constraints - Added `placeholder` field to `Input` struct matching OpenAPI spec - Removed redundant comments in favor of inline struct tags These changes improve code clarity and make the types more self-documenting, while maintaining compatibility with the OpenAPI schema definitions in `docs/reference/api/openapi.yaml`. --------- Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
This commit is contained in:
parent
ba609e1c17
commit
f870a4c000
3 changed files with 78 additions and 101 deletions
|
|
@ -131,7 +131,7 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
name: "invalid token",
|
||||
requestBody: apiv0.ServerJSON{
|
||||
Schema: model.CurrentSchemaURL,
|
||||
Name: "test-server",
|
||||
Name: "example/test-server",
|
||||
Description: "A test server",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
|
|
@ -252,8 +252,8 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
setupRegistryService: func(_ service.RegistryService) {},
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedError: "server name cannot contain multiple slashes",
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
expectedError: "expected string to match pattern",
|
||||
},
|
||||
{
|
||||
name: "invalid server name - multiple slashes (three slashes)",
|
||||
|
|
@ -270,8 +270,8 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
setupRegistryService: func(_ service.RegistryService) {},
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedError: "server name cannot contain multiple slashes",
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
expectedError: "expected string to match pattern",
|
||||
},
|
||||
{
|
||||
name: "invalid server name - consecutive slashes",
|
||||
|
|
@ -288,8 +288,8 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
setupRegistryService: func(_ service.RegistryService) {},
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedError: "server name cannot contain multiple slashes",
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
expectedError: "expected string to match pattern",
|
||||
},
|
||||
{
|
||||
name: "invalid server name - URL-like path",
|
||||
|
|
@ -306,8 +306,8 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
setupRegistryService: func(_ service.RegistryService) {},
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedError: "server name cannot contain multiple slashes",
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
expectedError: "expected string to match pattern",
|
||||
},
|
||||
{
|
||||
name: "invalid server name - many slashes",
|
||||
|
|
@ -324,8 +324,8 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
setupRegistryService: func(_ service.RegistryService) {},
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedError: "server name cannot contain multiple slashes",
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
expectedError: "expected string to match pattern",
|
||||
},
|
||||
{
|
||||
name: "invalid server name - with packages and remotes",
|
||||
|
|
@ -363,8 +363,8 @@ func TestPublishEndpoint(t *testing.T) {
|
|||
},
|
||||
},
|
||||
setupRegistryService: func(_ service.RegistryService) {},
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedError: "server name cannot contain multiple slashes",
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
expectedError: "expected string to match pattern",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -447,25 +447,25 @@ func TestPublishEndpoint_MultipleSlashesEdgeCases(t *testing.T) {
|
|||
{
|
||||
name: "invalid - trailing slash after valid name",
|
||||
serverName: "com.example/server/",
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
description: "Trailing slash creates multiple slashes",
|
||||
},
|
||||
{
|
||||
name: "invalid - leading and middle slash",
|
||||
serverName: "/com.example/server",
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
description: "Leading slash with middle slash",
|
||||
},
|
||||
{
|
||||
name: "invalid - file system style path",
|
||||
serverName: "usr/local/bin/server",
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
description: "File system style paths should be rejected",
|
||||
},
|
||||
{
|
||||
name: "invalid - version-like suffix",
|
||||
serverName: "com.example/server/v1.0.0",
|
||||
expectedStatus: http.StatusBadRequest,
|
||||
expectedStatus: http.StatusUnprocessableEntity,
|
||||
description: "Version suffixes with slash should be rejected",
|
||||
},
|
||||
}
|
||||
|
|
@ -517,9 +517,9 @@ func TestPublishEndpoint_MultipleSlashesEdgeCases(t *testing.T) {
|
|||
assert.Equal(t, tc.expectedStatus, rr.Code,
|
||||
"%s: expected status %d, got %d", tc.description, tc.expectedStatus, rr.Code)
|
||||
|
||||
if tc.expectedStatus == http.StatusBadRequest {
|
||||
assert.Contains(t, rr.Body.String(), "server name cannot contain multiple slashes",
|
||||
"%s: should contain specific error message", tc.description)
|
||||
if tc.expectedStatus == http.StatusUnprocessableEntity {
|
||||
assert.Contains(t, rr.Body.String(), "expected string to match pattern",
|
||||
"%s: should contain pattern validation error", tc.description)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,53 +6,46 @@ import (
|
|||
"github.com/modelcontextprotocol/registry/pkg/model"
|
||||
)
|
||||
|
||||
// RegistryExtensions represents registry-generated metadata
|
||||
type RegistryExtensions struct {
|
||||
Status model.Status `json:"status"`
|
||||
PublishedAt time.Time `json:"publishedAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt,omitempty"`
|
||||
IsLatest bool `json:"isLatest"`
|
||||
Status model.Status `json:"status" enum:"active,deprecated,deleted" doc:"Server lifecycle status"`
|
||||
PublishedAt time.Time `json:"publishedAt" format:"date-time" doc:"Timestamp when the server was first published to the registry"`
|
||||
UpdatedAt time.Time `json:"updatedAt,omitempty" format:"date-time" doc:"Timestamp when the server entry was last updated"`
|
||||
IsLatest bool `json:"isLatest" doc:"Whether this is the latest version of the server"`
|
||||
}
|
||||
|
||||
// ResponseMeta represents the top-level metadata in API responses
|
||||
type ResponseMeta struct {
|
||||
Official *RegistryExtensions `json:"io.modelcontextprotocol.registry/official,omitempty"`
|
||||
Official *RegistryExtensions `json:"io.modelcontextprotocol.registry/official,omitempty" doc:"Official MCP registry metadata"`
|
||||
}
|
||||
|
||||
// ServerResponse represents the new API response format with separated metadata
|
||||
type ServerResponse struct {
|
||||
Server ServerJSON `json:"server"`
|
||||
Meta ResponseMeta `json:"_meta"`
|
||||
Server ServerJSON `json:"server" doc:"Server configuration and metadata"`
|
||||
Meta ResponseMeta `json:"_meta" doc:"Registry-managed metadata"`
|
||||
}
|
||||
|
||||
// ServerListResponse represents the paginated server list response
|
||||
type ServerListResponse struct {
|
||||
Servers []ServerResponse `json:"servers"`
|
||||
Metadata Metadata `json:"metadata"`
|
||||
Servers []ServerResponse `json:"servers" doc:"List of server entries"`
|
||||
Metadata Metadata `json:"metadata" doc:"Pagination metadata"`
|
||||
}
|
||||
|
||||
// ServerMeta represents the structured metadata with known extension fields
|
||||
type ServerMeta struct {
|
||||
PublisherProvided map[string]interface{} `json:"io.modelcontextprotocol.registry/publisher-provided,omitempty"`
|
||||
PublisherProvided map[string]interface{} `json:"io.modelcontextprotocol.registry/publisher-provided,omitempty" doc:"Publisher-provided metadata for downstream registries"`
|
||||
}
|
||||
|
||||
// ServerJSON represents complete server information as defined in the MCP spec, with extension support
|
||||
type ServerJSON struct {
|
||||
Schema string `json:"$schema" required:"true" minLength:"1"`
|
||||
Name string `json:"name" minLength:"1" maxLength:"200"`
|
||||
Description string `json:"description" minLength:"1" maxLength:"100"`
|
||||
Title string `json:"title,omitempty" minLength:"1" maxLength:"100"`
|
||||
Repository model.Repository `json:"repository,omitempty"`
|
||||
Version string `json:"version"`
|
||||
WebsiteURL string `json:"websiteUrl,omitempty"`
|
||||
Icons []model.Icon `json:"icons,omitempty"`
|
||||
Packages []model.Package `json:"packages,omitempty"`
|
||||
Remotes []model.Transport `json:"remotes,omitempty"`
|
||||
Meta *ServerMeta `json:"_meta,omitempty"`
|
||||
Schema string `json:"$schema" required:"true" minLength:"1" format:"uri" doc:"JSON Schema URI for this server.json format" example:"https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json"`
|
||||
Name string `json:"name" minLength:"3" maxLength:"200" pattern:"^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$" doc:"Server name in reverse-DNS format. Must contain exactly one forward slash separating namespace from server name." example:"io.github.user/weather"`
|
||||
Description string `json:"description" minLength:"1" maxLength:"100" doc:"Clear human-readable explanation of server functionality." example:"MCP server providing weather data and forecasts via OpenWeatherMap API"`
|
||||
Title string `json:"title,omitempty" minLength:"1" maxLength:"100" doc:"Optional human-readable title or display name for the MCP server." example:"Weather API"`
|
||||
Repository model.Repository `json:"repository,omitempty" doc:"Optional repository metadata for the MCP server source code."`
|
||||
Version string `json:"version" doc:"Version string for this server. SHOULD follow semantic versioning." example:"1.0.2"`
|
||||
WebsiteURL string `json:"websiteUrl,omitempty" format:"uri" doc:"Optional URL to the server's homepage, documentation, or project website." example:"https://modelcontextprotocol.io/examples"`
|
||||
Icons []model.Icon `json:"icons,omitempty" doc:"Optional set of sized icons that the client can display in a user interface."`
|
||||
Packages []model.Package `json:"packages,omitempty" doc:"Array of package configurations"`
|
||||
Remotes []model.Transport `json:"remotes,omitempty" doc:"Array of remote configurations"`
|
||||
Meta *ServerMeta `json:"_meta,omitempty" doc:"Extension metadata using reverse DNS namespacing for vendor-specific data"`
|
||||
}
|
||||
|
||||
// Metadata represents pagination metadata
|
||||
type Metadata struct {
|
||||
NextCursor string `json:"nextCursor,omitempty"`
|
||||
Count int `json:"count"`
|
||||
NextCursor string `json:"nextCursor,omitempty" doc:"Pagination cursor for retrieving the next page of results. Use this exact value in the cursor query parameter of your next request."`
|
||||
Count int `json:"count" doc:"Number of items in current page"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package model
|
||||
|
||||
// Status represents the lifecycle status of a server
|
||||
type Status string
|
||||
|
||||
const (
|
||||
|
|
@ -9,11 +8,10 @@ const (
|
|||
StatusDeleted Status = "deleted"
|
||||
)
|
||||
|
||||
// Transport represents transport configuration with optional URL templating
|
||||
type Transport struct {
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Headers []KeyValueInput `json:"headers,omitempty"`
|
||||
Type string `json:"type" doc:"Transport type (stdio, streamable-http, or sse)" example:"stdio"`
|
||||
URL string `json:"url,omitempty" doc:"URL for streamable-http or sse transports" example:"https://api.example.com/mcp"`
|
||||
Headers []KeyValueInput `json:"headers,omitempty" doc:"HTTP headers for streamable-http or sse transports"`
|
||||
}
|
||||
|
||||
// Package represents a package configuration.
|
||||
|
|
@ -25,39 +23,37 @@ type Transport struct {
|
|||
// - MCPB: RegistryType, Identifier (download URL), FileSHA256 (required)
|
||||
type Package struct {
|
||||
// RegistryType indicates how to download packages (e.g., "npm", "pypi", "oci", "nuget", "mcpb")
|
||||
RegistryType string `json:"registryType" minLength:"1"`
|
||||
RegistryType string `json:"registryType" minLength:"1" doc:"Registry type indicating how to download packages (e.g., 'npm', 'pypi', 'oci', 'nuget', 'mcpb')" example:"npm"`
|
||||
// RegistryBaseURL is the base URL of the package registry (used by npm, pypi, nuget; not used by oci, mcpb)
|
||||
RegistryBaseURL string `json:"registryBaseUrl,omitempty"`
|
||||
RegistryBaseURL string `json:"registryBaseUrl,omitempty" format:"uri" doc:"Base URL of the package registry" example:"https://registry.npmjs.org"`
|
||||
// Identifier is the package identifier:
|
||||
// - For NPM/PyPI/NuGet: package name or ID
|
||||
// - For OCI: full image reference (e.g., "ghcr.io/owner/repo:v1.0.0")
|
||||
// - For MCPB: direct download URL
|
||||
Identifier string `json:"identifier" minLength:"1"`
|
||||
Identifier string `json:"identifier" minLength:"1" doc:"Package identifier - either a package name (for registries) or URL (for direct downloads)" example:"@modelcontextprotocol/server-brave-search"`
|
||||
// Version is the package version (used by npm, pypi, nuget; not used by oci, mcpb where version is in the identifier)
|
||||
Version string `json:"version,omitempty" minLength:"1"`
|
||||
Version string `json:"version,omitempty" minLength:"1" doc:"Package version. Must be a specific version. Version ranges are rejected (e.g., '^1.2.3', '~1.2.3', '>=1.2.3', '1.x', '1.*')." example:"1.0.2"`
|
||||
// FileSHA256 is the SHA-256 hash for integrity verification (required for mcpb, optional for others)
|
||||
FileSHA256 string `json:"fileSha256,omitempty"`
|
||||
FileSHA256 string `json:"fileSha256,omitempty" pattern:"^[a-f0-9]{64}$" doc:"SHA-256 hash of the package file for integrity verification. Required for MCPB packages and optional for other package types. Authors are responsible for generating correct SHA-256 hashes when creating server.json. If present, MCP clients must validate the downloaded file matches the hash before running packages to ensure file integrity." example:"fe333e598595000ae021bd27117db32ec69af6987f507ba7a63c90638ff633ce"`
|
||||
// RunTimeHint suggests the appropriate runtime for the package
|
||||
RunTimeHint string `json:"runtimeHint,omitempty"`
|
||||
RunTimeHint string `json:"runtimeHint,omitempty" doc:"A hint to help clients determine the appropriate runtime for the package. This field should be provided when runtimeArguments are present." example:"npx"`
|
||||
// Transport is required and specifies the transport protocol configuration
|
||||
Transport Transport `json:"transport"`
|
||||
Transport Transport `json:"transport" doc:"Transport protocol configuration for the package"`
|
||||
// RuntimeArguments are passed to the package's runtime command (e.g., docker, npx)
|
||||
RuntimeArguments []Argument `json:"runtimeArguments,omitempty"`
|
||||
RuntimeArguments []Argument `json:"runtimeArguments,omitempty" doc:"A list of arguments to be passed to the package's runtime command (such as docker or npx). The runtimeHint field should be provided when runtimeArguments are present."`
|
||||
// PackageArguments are passed to the package's binary
|
||||
PackageArguments []Argument `json:"packageArguments,omitempty"`
|
||||
PackageArguments []Argument `json:"packageArguments,omitempty" doc:"A list of arguments to be passed to the package's binary."`
|
||||
// EnvironmentVariables are set when running the package
|
||||
EnvironmentVariables []KeyValueInput `json:"environmentVariables,omitempty"`
|
||||
EnvironmentVariables []KeyValueInput `json:"environmentVariables,omitempty" doc:"A mapping of environment variables to be set when running the package."`
|
||||
}
|
||||
|
||||
// Repository represents a source code repository as defined in the spec
|
||||
type Repository struct {
|
||||
URL string `json:"url"`
|
||||
Source string `json:"source"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Subfolder string `json:"subfolder,omitempty"`
|
||||
URL string `json:"url" format:"uri" doc:"Repository URL for browsing source code. Should support both web browsing and git clone operations." example:"https://github.com/modelcontextprotocol/servers"`
|
||||
Source string `json:"source" doc:"Repository hosting service identifier. Used by registries to determine validation and API access methods." example:"github"`
|
||||
ID string `json:"id,omitempty" doc:"Repository identifier from the hosting service (e.g., GitHub repo ID). Owned and determined by the source forge. Should remain stable across repository renames and may be used to detect repository resurrection attacks - if a repository is deleted and recreated, the ID should change. For GitHub, use: gh api repos/<owner>/<repo> --jq '.id'" example:"b94b5f7e-c7c6-d760-2c78-a5e9b8a5b8c9"`
|
||||
Subfolder string `json:"subfolder,omitempty" doc:"Optional relative path from repository root to the server location within a monorepo or nested package structure. Must be a clean relative path." example:"src/everything"`
|
||||
}
|
||||
|
||||
// Format represents the input format type
|
||||
type Format string
|
||||
|
||||
const (
|
||||
|
|
@ -67,30 +63,27 @@ const (
|
|||
FormatFilePath Format = "filepath"
|
||||
)
|
||||
|
||||
// Input represents a configuration input
|
||||
type Input struct {
|
||||
Description string `json:"description,omitempty"`
|
||||
IsRequired bool `json:"isRequired,omitempty"`
|
||||
Format Format `json:"format,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
IsSecret bool `json:"isSecret,omitempty"`
|
||||
Default string `json:"default,omitempty"`
|
||||
Choices []string `json:"choices,omitempty"`
|
||||
Description string `json:"description,omitempty" doc:"A description of the input, which clients can use to provide context to the user."`
|
||||
IsRequired bool `json:"isRequired,omitempty" doc:"Whether the input is required"`
|
||||
Format Format `json:"format,omitempty" enum:"string,number,boolean,filepath" doc:"Specifies the input format. Supported values include filepath, which should be interpreted as a file on the user's filesystem."`
|
||||
Value string `json:"value,omitempty" doc:"The value for the input. If this is not set, the user may be prompted to provide a value. Identifiers wrapped in {curly_braces} will be replaced with the corresponding properties from the input variables map."`
|
||||
IsSecret bool `json:"isSecret,omitempty" doc:"Indicates whether the input is a secret value (e.g., password, token). If true, clients should handle the value securely."`
|
||||
Default string `json:"default,omitempty" doc:"The default value for the input. This should be a valid value for the input. If you want to provide input examples or guidance, use the placeholder field instead."`
|
||||
Placeholder string `json:"placeholder,omitempty" doc:"A placeholder for the input to be displaying during configuration. This is used to provide examples or guidance about the expected form or content of the input."`
|
||||
Choices []string `json:"choices,omitempty" doc:"A list of possible values for the input. If provided, the user must select one of these values."`
|
||||
}
|
||||
|
||||
// InputWithVariables represents an input that can contain variables
|
||||
type InputWithVariables struct {
|
||||
Input `json:",inline"`
|
||||
Variables map[string]Input `json:"variables,omitempty"`
|
||||
Variables map[string]Input `json:"variables,omitempty" doc:"A map of variable names to their values. Keys in the input value that are wrapped in {curly_braces} will be replaced with the corresponding variable values."`
|
||||
}
|
||||
|
||||
// KeyValueInput represents a named input with variables
|
||||
type KeyValueInput struct {
|
||||
InputWithVariables `json:",inline"`
|
||||
Name string `json:"name"`
|
||||
Name string `json:"name" doc:"Name of the header or environment variable." example:"SOME_VARIABLE"`
|
||||
}
|
||||
|
||||
// ArgumentType represents the type of argument
|
||||
type ArgumentType string
|
||||
|
||||
const (
|
||||
|
|
@ -98,26 +91,17 @@ const (
|
|||
ArgumentTypeNamed ArgumentType = "named"
|
||||
)
|
||||
|
||||
// Argument defines a type that can be either a PositionalArgument or a NamedArgument
|
||||
type Argument struct {
|
||||
InputWithVariables `json:",inline"`
|
||||
Type ArgumentType `json:"type"`
|
||||
Name string `json:"name,omitempty"`
|
||||
IsRepeated bool `json:"isRepeated,omitempty"`
|
||||
ValueHint string `json:"valueHint,omitempty"`
|
||||
Type ArgumentType `json:"type" doc:"Argument type: 'positional' or 'named'" example:"positional"`
|
||||
Name string `json:"name,omitempty" doc:"The flag name (for named arguments), including any leading dashes. Empty for positional arguments." example:"--port"`
|
||||
ValueHint string `json:"valueHint,omitempty" doc:"An identifier for positional arguments. Used in transport URL variable substitution." example:"file_path"`
|
||||
IsRepeated bool `json:"isRepeated,omitempty" doc:"Whether the argument can be repeated multiple times."`
|
||||
}
|
||||
|
||||
// Icon represents an optionally-sized icon that can be displayed in a user interface
|
||||
type Icon struct {
|
||||
// Src is a standard URI pointing to an icon resource (HTTPS URL only for registry)
|
||||
Src string `json:"src" required:"true" format:"uri" maxLength:"255"`
|
||||
// MimeType is an optional MIME type override if the source MIME type is missing or generic
|
||||
MimeType *string `json:"mimeType,omitempty" enum:"image/png,image/jpeg,image/jpg,image/svg+xml,image/webp"`
|
||||
// Sizes is an optional array of strings that specify sizes at which the icon can be used
|
||||
// Each string should be in WxH format (e.g., "48x48", "96x96") or "any" for scalable formats
|
||||
Sizes []string `json:"sizes,omitempty" pattern:"^(\\d+x\\d+|any)$"`
|
||||
// Theme is an optional specifier for the theme this icon is designed for
|
||||
// "light" indicates the icon is designed for light backgrounds
|
||||
// "dark" indicates the icon is designed for dark backgrounds
|
||||
Theme *string `json:"theme,omitempty" enum:"light,dark"`
|
||||
Src string `json:"src" required:"true" format:"uri" maxLength:"255" doc:"A standard URI pointing to an icon resource. Must be an HTTPS URL. Consumers SHOULD take steps to ensure URLs serving icons are from the same domain as the server or a trusted domain. Consumers SHOULD take appropriate precautions when consuming SVGs as they can contain executable JavaScript." example:"https://example.com/icon.png"`
|
||||
MimeType *string `json:"mimeType,omitempty" enum:"image/png,image/jpeg,image/jpg,image/svg+xml,image/webp" doc:"Optional MIME type override if the source MIME type is missing or generic. Must be one of: image/png, image/jpeg, image/jpg, image/svg+xml, image/webp." example:"image/png"`
|
||||
Sizes []string `json:"sizes,omitempty" doc:"Optional array of strings that specify sizes at which the icon can be used. Each string should be in WxH format (e.g., '48x48', '96x96') or 'any' for scalable formats like SVG. If not provided, the client should assume that the icon can be used at any size." items.pattern:"^(\\d+x\\d+|any)$"`
|
||||
Theme *string `json:"theme,omitempty" enum:"light,dark" doc:"Optional specifier for the theme this icon is designed for. 'light' indicates the icon is designed to be used with a light background, and 'dark' indicates the icon is designed to be used with a dark background. If not provided, the client should assume the icon can be used with any theme."`
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue