entity

package
v1.21.55 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package entity is the canonical home for clicky's entity + operation model: the entity registry and CLI generation (Entity, EntityBuilder, RegisterEntity, GenerateCLI), the command-function registries (AddCommand, the cobra annotation metadata), the RPC operation model (RPCOperation, Schema, …), and named, reusable filter/lookup definitions that work across both static (Go-struct) and dynamic (JSON-Schema) entities.

A filter is defined once — in Go via RegisterFilter, or declaratively via RegisterFilterSpec — and reused by name from any number of entities. The core abstraction (FilterSource + FilterContext) never sees a typed ListOpts, so the same definition serves a compile-time Go entity and a schema-driven dynamic entity identically.

On a static entity, attach a named filter with the typed adapter:

clicky.NewEntity[Task, TaskOpts, Task]("tasks").
	Filters(entity.Use[TaskOpts]("users").As("owner")).
	List(listTasks).
	Register()

The dependency runs one way: this package depends only on clicky subpackages (api, flags, formatters, task) plus cobra/pflag — never on the root clicky package. The root clicky package imports this one and re-exports the model via type aliases and thin wrappers (see entity_aliases.go), so callers keep using clicky.NewEntity, clicky.Entity, clicky.RegisterEntity, etc. unchanged. Host-owned globals (the CLI format flags, HTTPie argument parsing) are injected through the RenderResult / ParseArgs hooks in render.go.

Index

Constants

View Source
const (
	AnnotationClickyToolGroup             = annotationClickyToolGroup
	AnnotationClickyToolTitle             = annotationClickyToolTitle
	AnnotationClickyToolIcon              = annotationClickyToolIcon
	AnnotationClickyToolParent            = annotationClickyToolParent
	AnnotationClickyToolReadOnlyHint      = annotationClickyToolReadOnlyHint
	AnnotationClickyToolDestructiveHint   = annotationClickyToolDestructive
	AnnotationClickyToolIdempotentHint    = annotationClickyToolIdempotent
	AnnotationClickyToolOpenWorldHint     = annotationClickyToolOpenWorld
	AnnotationClickyToolDefaultPermission = annotationClickyToolPermission
	AnnotationClickyToolStrict            = annotationClickyToolStrict
)
View Source
const (
	ScopePage = "page"
	ScopeAll  = "all"
)

Export scopes. A request either asks for one page or for everything up to the operation's ceiling; there is no third answer, so anything else is refused rather than quietly treated as a page.

View Source
const (
	ModePage      = "page"
	ModeBuffered  = "buffered"
	ModeStreaming = "streaming"
)

Export modes describe how the rows were produced, which is orthogonal to the scope that was asked for: a scope=page request against an operation that has to run its whole pipeline before any row is correct reports ModeBuffered.

View Source
const (
	// DefaultPageSize is the page an operation serves when the caller names none.
	DefaultPageSize = 100
	// DefaultMaxPageSize is the largest single page a caller may ask for. Past
	// this, the answer is scope=all rather than a bigger page.
	DefaultMaxPageSize = 1000
)

These are the library's own fallbacks, applied only when a caller states no PageLimits. An application with a view on how much its backends can serve is expected to pass its own; nothing here is claimed to match any consumer's.

View Source
const (
	SourceStatic = "static"
	SourceEntity = "entity"
	SourceFunc   = "func" // Go-only; not constructible from a spec.
	SourceCustom = "custom"
)

Source kinds for the declarative FilterSourceSpec.

View Source
const DefaultExportFormat = "json"

DefaultExportFormat is what a caller that expressed no preference gets.

View Source
const InternalErrorMessage = "internal server error"

InternalErrorMessage is the body message every unclassified failure is reported with, so an internal detail can never reach a client by accident.

View Source
const MaxLookupOptions = lookupOptionsLimit

MaxLookupOptions is lookupOptionsLimit exported, so a caller declaring a per-filter Limit can validate it against the ceiling rather than discovering at request time that it was silently reduced.

View Source
const PathSeparator = "/"

PathSeparator is the wire delimiter for ClickySurface.Path. Producers split their own naming convention (dots, slashes, colons — whatever the domain uses) with SplitPath and emit the result joined by this, so a frontend never has to know, or guess, the producer's convention.

Variables

View Source
var ParseArgs = func(args []string) (map[string]any, error) {
	return nil, fmt.Errorf("entity.ParseArgs not configured: the root clicky package must wire it")
}

ParseArgs parses HTTPie-style positional arguments (key=value, key:=json, …) into a body map for create/update commands. Root clicky wires it in init() to its ParseArgumentsAsMap; the default fails loudly so a missing wiring surfaces rather than silently dropping arguments.

View Source
var RenderResult = func(o any) error { return nil }

RenderResult renders a command result through the host application's format pipeline — the global --format/--output flags and any configured sinks. Root clicky wires it in init() (to ParseFormatSpec + PrintAndWriteSinks against its global Flags); the default no-op lets the entity package's own unit tests run without a renderer.

It is a package-level hook rather than a direct dependency so the entity package stays free of the root clicky package (which owns the global flag state) — preserving the one-way entity → clicky-subpackages dependency.

Functions

func AcceptedFormat added in v1.21.55

func AcceptedFormat(accept string) (string, error)

AcceptedFormat picks the format an Accept header asks for.

Accept is ranked, not ordered: a caller listing text/html first at q=0.1 and the clicky envelope at q=0.9 is asking for the envelope. Reading the first recognised entry answers with the one it weighted lowest. Ties keep the earlier entry, which is the order the caller wrote them in.

A q=0 is a refusal, not a low preference, and a refusal has to be able to leave nothing acceptable behind. Seeding the search with the default format would make `Accept: application/json;q=0` answer with the very thing it just refused, so refusals are tracked and the fallback is withheld when the default is among them — the honest answer there is 406. A wildcard resolves to the default for exactly this reason, so `*/*;q=0` refuses everything rather than silently accepting the default.

A refusal only decides the answer when nothing else was acceptable, which is what lets a named range override a blanket one: `*/*;q=0, text/csv` is a caller that wants csv and nothing else.

func AddCommand

func AddCommand[T any, R any](parent *cobra.Command, opts T, fn func(opts T) (R, error)) *cobra.Command

AddCommand creates a Cobra command with automatic flag parsing from struct tags, execution, and result formatting.

Type parameter T must be a struct with tags defining flags:

  • flag:"name" - flag name (required)
  • help:"description" - flag help text
  • default:"value" - default value
  • short:"x" - short flag variant
  • required:"true" - mark flag as required
  • stdin:"true" - mark field as default for stdin input (only one field)

Supports @ prefix for file/URL loading:

  • @file.txt - read from file
  • @https://... - fetch from URL
  • For slices: one value per line (skip empty lines and # comments)
  • For slices: @file.csv:ColumnName reads a named column from a CSV (first row is the header, empty cells are skipped)
  • For slices: @file.xlsx:ColumnName / @file.xls:ColumnName reads a named column from the first worksheet (case-insensitive header match)

Supported types:

  • string, int, bool
  • duration.Duration (supports "30d", "2w", etc.)
  • time.Time (supports datamath like "now-7d", "now/d", "now-1M/M")
  • []string, []int (slices)

Datamath expressions for time.Time fields (Elasticsearch compatible):

  • now : current time
  • now-7d : 7 days ago
  • now+2h : 2 hours from now
  • now/d : start of current day
  • now-7d/d : start of day 7 days ago
  • now/w : start of this week
  • now-1M/M : start of last month
  • now/y : start of this year
  • Units: y (year), M (month), w (week), d (day), h (hour), m (minute), s (second)

Example:

type ListOptions struct {
    Role   string            `flag:"role" help:"Filter by role" short:"r"`
    Limit  int               `flag:"limit" help:"Max results" default:"50"`
    Since  time.Time         `flag:"since" help:"Created since" default:"now-30d"`
    Tags   []string          `flag:"tags" help:"Filter tags" stdin:"true"`
    MaxAge duration.Duration `flag:"max-age" help:"Max age" default:"365d"`
}

cmd := &cobra.Command{Use: "list", Short: "List users"}
clicky.AddCommand(cmd, ListOptions{}, func(opts ListOptions) (any, error) {
    return fetchUsers(opts)
})

Usage examples:

myapp list --tags @tags.txt              # load from file
myapp list --since now-30d               # datamath
echo -e "tag1\ntag2" | myapp list        # stdin
myapp list --max-age 60d --json          # with formatting

func AddCommandWithContext

func AddCommandWithContext[T any, R any](parent *cobra.Command, opts T, fn func(ctx context.Context, opts T) (R, error)) *cobra.Command

AddCommandWithContext is AddCommand whose closure receives the request-scoped context (cmd.Context() on the CLI, r.Context() over HTTP). It derives the command name from the opts struct exactly like AddCommand, then delegates to AddNamedCommandWithContext so the subcommand can resolve a per-request database/config instead of a process global.

func AddNamedCommand

func AddNamedCommand[T any, R any](name string, parent *cobra.Command, opts T, fn func(opts T) (R, error)) *cobra.Command

func AddNamedCommandWithContext

func AddNamedCommandWithContext[T any, R any](name string, parent *cobra.Command, opts T, fn func(ctx context.Context, opts T) (R, error)) *cobra.Command

AddNamedCommandWithContext is AddNamedCommand whose closure receives the request-scoped context (cmd.Context() on the CLI, r.Context() over HTTP), so the subcommand can resolve a per-request database/config instead of a process global. Same flag/arg binding and rendering as AddNamedCommand.

func AnnotateTool added in v1.21.38

func AnnotateTool(cmd *cobra.Command, hints MCPToolHints)

AnnotateTool attaches MCP-facing tool hints to cmd. It is the public helper for commands that are not generated from an EntityBuilder.

func ContentDisposition added in v1.21.55

func ContentDisposition(filename string) string

ContentDisposition renders an attachment header for a filename.

RFC 6266's plain filename= is a quoted-string, which is ISO-8859-1: a UTF-8 name written there travels as bytes the client is not obliged to decode, and Go's own quoting is not the escaping that header defines either. filename* names its charset, so it is the form that carries a non-ASCII name intact. Both are emitted — a client that understands filename* is required to prefer it, and one that does not still gets a usable, if flattened, name.

func DeclaresTruncatedTrailer added in v1.21.55

func DeclaresTruncatedTrailer(req PageRequest, res PageResponse) bool

DeclaresTruncatedTrailer reports whether this response has to declare Trailer: X-Truncated, and so whether it is a response that ends with trailers at all.

Only a ceiling that might still bite needs one. A buffered export has none to hit, and one already known to have been cut has its answer in the headers — declaring a trailer for either costs the response its Content-Length, forces chunked encoding, and promises an answer that never comes.

A trailer is a poor last resort: browsers do not expose them, so this reaches CLI and library callers only. It is kept for the one case that is genuinely unknowable up front — a stream whose backend states no total — rather than as the primary channel.

It is exported because the transport has to know the same thing to send the trailer it declares, and to know whether anything else may ride along in the trailer section it has already paid for. Two copies of this condition is the worst outcome available: a declared trailer that never arrives leaves a client waiting, and an undeclared one is dropped on the floor.

func ExportContentType added in v1.21.55

func ExportContentType(format string) string

func ExportExtension added in v1.21.55

func ExportExtension(format string) string

func ExportHeaderNames added in v1.21.55

func ExportHeaderNames() []string

ExportHeaderNames are the header names, for Access-Control-Expose-Headers.

func ExportResponseHeaders added in v1.21.55

func ExportResponseHeaders() map[string]ExportHeaderDoc

ExportResponseHeaders documents the same headers for the OpenAPI response.

func GenerateCLI

func GenerateCLI(parent *cobra.Command)

GenerateCLI creates cobra subcommands for all registered entities under parent. Admin entities are nested under a shared "admin" parent command. Entities with a Parent set are nested under a shared parent cobra command, created lazily if it does not already exist.

func GetDataFunc

func GetDataFunc(cmd *cobra.Command) func(flags map[string]string, args []string) (any, error)

GetDataFunc returns the direct data function registered for a command, if any. Used by the RPC converter to wire DataFunc on RPCOperation.

func GetLookupFunc

func GetLookupFunc(cmd *cobra.Command) func(flags map[string]string, args []string) (any, error)

GetLookupFunc returns the direct lookup function registered for a command, if any.

func IsLocalOnly added in v1.21.55

func IsLocalOnly(cmd *cobra.Command) bool

IsLocalOnly reports whether a command, or any command it is nested under, is marked local-only.

func IsTabularExport added in v1.21.55

func IsTabularExport(format string) bool

IsTabularExport reports whether a format renders rows as a table, and so has to be written through formatters.WriteTableStream rather than serialized.

func JoinPath added in v1.21.55

func JoinPath(segments []string) string

JoinPath renders segments as a ClickySurface.Path. Empty segments are dropped so the output always round-trips through SplitPath(_, PathSeparator).

func MarkLocalOnly added in v1.21.55

func MarkLocalOnly(cmd *cobra.Command)

MarkLocalOnly keeps a command off the generated HTTP surface.

Publishing a CLI as an API publishes every runnable command in the tree, which is wrong for the ones that administer the process rather than serve a resource: `serve` would start a nested server, and `migrate` would let an unauthenticated request alter the schema. Such commands stay in `--help` and on the CLI — they are simply not routes.

It marks the whole subtree: marking a parent covers every subcommand under it.

func RegisterDynamicEntity

func RegisterDynamicEntity(spec DynamicEntitySpec)

RegisterDynamicEntity registers a schema-driven entity assembled at runtime (no compile-time Go struct). It is the single root entrypoint the entity package's dynamic builder targets; everything downstream — GenerateCLI, RPC, OpenAPI, the lookup endpoint — consumes it through the normal entity registry.

func RegisterDynamicEntityFamily added in v1.21.55

func RegisterDynamicEntityFamily(family DynamicEntityFamily)

RegisterDynamicEntityFamily registers a family, replacing any family already registered under the same Name.

Replacing rather than appending is deliberate: a family is a route, not an instance, and two families claiming one path segment is a wiring bug that would otherwise surface as whichever registration happened to be found first.

Register every family before the server builds its mux (rpc.RegisterRoutes). The mux pattern for a family is written once, from the families registered at that moment: a family registered afterwards is described by the OpenAPI document — which is resolved per request — but has no pattern, so the mux answers 404 before the family dispatch is ever reached. Unregistering has the mirror shape: the pattern stays, and the path falls through to ordinary operation lookup and 404s there.

Name must not collide with the first path segment of a registered operation. The dispatch resolves a registered operation first, so a colliding family is simply never reached for the paths the operation owns.

func RegisterEntity

func RegisterEntity[T EntityItem, ListOpts any, R any](e Entity[T, ListOpts, R])

RegisterEntity registers a CRUD entity. Call during init(). CLI commands and HTTP routes are generated later via GenerateCLI/GenerateRoutes.

See the github.com/flanksource/clicky/entity package for the authoring guide and the best practices for operations that work well across CLI and HTTP.

func RegisterFilter

func RegisterFilter(f NamedFilter)

RegisterFilter registers a named filter for reuse across entities. It panics on a duplicate name or an incomplete definition — registration happens at init/setup time, so a collision is a programming error that must fail loudly.

func RegisterFilterSpec

func RegisterFilterSpec(s FilterSpec)

RegisterFilterSpec registers a declaratively-defined named filter. Like RegisterFilter it is a setup-time call and panics on an invalid spec.

func RegisterSubCommand

func RegisterSubCommand(parentName string, cmd *cobra.Command)

RegisterSubCommand defers attaching cmd as a child of a parent cobra command identified by parentName. The attachment is performed by GenerateCLI after all entity parents have been created. If no command at parentName exists after entity generation, a thin parent command is created to host cmd.

parentName may be a bare command name ("policy") or a slash-delimited path ("billing/policy"). A path is resolved one segment at a time beneath root; missing intermediates are created as thin grouping commands, and existing nodes (including entity-generated parents) are reused.

Use this for non-entity cobra commands that should live under an entity-generated parent (or under an arbitrary grouping command).

func RegisterSubCommandFn

func RegisterSubCommandFn(parentName string, build func(parent *cobra.Command))

RegisterSubCommandFn defers running build against a parent cobra command identified by parentName. Use this when the subcommand needs to be constructed lazily — e.g. AddNamedCommand which both builds and attaches in one call.

parentName accepts the same bare-name-or-slash-path form as RegisterSubCommand.

Example:

clicky.RegisterSubCommandFn("correspondence", func(parent *cobra.Command) {
    clicky.AddNamedCommand("validate", parent, ValidateOptions{}, runValidate)
})

func RequestedFormat added in v1.21.55

func RequestedFormat(r *http.Request) (string, error)

RequestedFormat resolves ?format, falling back to content negotiation.

func ResolveDynamicLookup added in v1.21.55

func ResolveDynamicLookup(ctx context.Context, spec DynamicEntitySpec, flags map[string]string) (any, error)

ResolveDynamicLookup answers a filter-metadata lookup from a resolved spec.

A registered entity reaches this resolution through the LookupFunc the registry built for it. A family instance never enters the registry, so the transport has to enter the same resolution from the spec it just resolved — otherwise a runtime entity would be the one kind that cannot describe its own filters.

func SanitizeExportFilename added in v1.21.55

func SanitizeExportFilename(filename string) string

SanitizeExportFilename reduces a caller-supplied name to something that can only ever be a filename: no path to escape with, and nothing that could close the header parameter it is about to be written into.

func SetCORSHeaders added in v1.21.55

func SetCORSHeaders(w http.ResponseWriter)

SetCORSHeaders permits a cross-origin caller to read this response, whatever it turns out to be.

It is deliberately independent of the response: none of it depends on the rows, so it is set before the first thing that can fail. Setting it only on success is what makes an error body unreadable in a browser — and an error nobody can read is worse than the one it describes.

func SetCommandResponseMeta

func SetCommandResponseMeta(cmd *cobra.Command, meta ResponseOpenAPIMeta)

SetCommandResponseMeta attaches static response metadata to a command.

func SetExportAllowedOrigin added in v1.21.55

func SetExportAllowedOrigin(origin string)

SetExportAllowedOrigin narrows Access-Control-Allow-Origin on every export response to a single origin. A consumer that serves its frontend from a known origin should set it at startup; leaving it unset (or passing "") keeps the permissive "*" a library with no knowledge of its host has to default to.

func SetExportHeaders added in v1.21.55

func SetExportHeaders(w http.ResponseWriter, name string, req PageRequest, res PageResponse)

SetExportHeaders writes every paging fact this response carries. It must be called before the first byte of the body.

func SplitPath added in v1.21.55

func SplitPath(name, delimiters string) []string

SplitPath breaks name into hierarchy segments on any rune in delimiters, dropping empty segments so repeated or leading separators are harmless. Runes outside delimiters are never separators — SplitPath("a-b.c", ".") yields ["a-b", "c"], not three segments.

PathSeparator is always a separator, whatever delimiters says (including when it is empty): a segment containing it would be re-split by any consumer of the JoinPath output, so SplitPath("jms/api.incoming", ".") yields ["jms", "api", "incoming"] and the round-trip through JoinPath is stable.

A name with no delimiter yields a single segment, i.e. a root-level leaf.

func SupportedExportFormat added in v1.21.55

func SupportedExportFormat(format string) bool

func UnregisterDynamicEntityFamily added in v1.21.55

func UnregisterDynamicEntityFamily(name string) bool

UnregisterDynamicEntityFamily removes a family by name, reporting whether one was registered. A family whose backing store is gone — a tenant disconnected, a plugin unloaded — has to be able to take its route with it.

func Use

func Use[ListOpts any](filterName string) *attachedFilter[ListOpts]

Use attaches a registered named filter to a typed (static) entity. The returned value implements clicky.Filter[ListOpts] (plus the searchable/context/typed extensions) so it drops straight into Entity.Filters. By default it binds to the flag/field named after the filter; override with As.

Filters(entity.Use[TaskOpts]("users").As("owner"))

Use resolves the filter eagerly and panics if the name is unregistered, so a wiring mistake fails at setup rather than at request time.

func WriteError added in v1.21.55

func WriteError(w http.ResponseWriter, err error)

WriteError writes any error in the same shape, so a caller never has to choose between two error formats depending on where the failure came from.

An error that did not state a status is a bug rather than a refusal, so it becomes a 500 with an opaque code and a fixed message. Its own text is not forwarded: an unclassified error is whatever the failing dependency said, and that routinely names hosts, DSNs, file paths, or credentials. The detail stays server-side in the log; a handler that wants the client to see a reason must classify the failure with a StatusError.

Types

type ActionFlags

type ActionFlags interface {
	ClickyActionFlags()
}

ActionFlags is a marker interface implemented by options structs that declare typed cobra flags for a clicky Action. When an Action's Flags field is non-nil, the concrete type of the value is reflected for its `flag:"..."` struct tags and those flags are bound to the generated action cobra command.

Implementers attach a no-op `ClickyActionFlags()` method to an options struct, then pass a zero value of that struct in `Action.Flags`.

type ActionInfo

type ActionInfo struct {
	Name     string
	Short    string
	Method   string
	DataFunc func(flags map[string]string, args []string) (any, error)
	// ContextDataFunc, when set, is preferred over DataFunc by both the CLI run
	// path (fed cmd.Context()) and the RPC executor (fed r.Context()), mirroring
	// the entity CRUD seam. Lets an action resolve request-scoped state instead
	// of process globals.
	ContextDataFunc ContextDataFunc
	// FlagsType, if non-nil, is the struct type whose `flag:"..."` tagged
	// fields are registered as cobra flags on the generated action command
	// and populated into the flag map passed to DataFunc.
	FlagsType    reflect.Type
	ResponseType reflect.Type
	// OptionalID, when true, makes the positional <id> argument optional on
	// the generated action command — the action is invokable with no
	// argument (and the `id` passed to the run func is empty). Use for
	// actions whose target is supplied entirely through flags.
	OptionalID bool
	// ToolGroup overrides the entity's tool group for this action only. Empty
	// means the action inherits the entity's group.
	ToolGroup string
	ToolHints MCPToolHints
}

ActionInfo is the type-erased representation of a single-entity action.

type ActionSpec

type ActionSpec[R any] struct {
	// contains filtered or unexported fields
}

func Action

func Action[R any](name string, fn func(id string, flags map[string]string) (R, error)) *ActionSpec[R]

Action creates a typed custom operation on a single entity by ID.

func ActionWithContext

func ActionWithContext[R any](name string, fn func(ctx context.Context, id string, flags map[string]string) (R, error)) *ActionSpec[R]

ActionWithContext creates a typed action whose run closure receives the request-scoped context (cmd.Context() on the CLI, r.Context() over HTTP), so it can resolve a per-request database/config instead of a process global.

func ActionWithFlags

func ActionWithFlags[R any](name string, flags ActionFlags, fn func(id string, flags map[string]string) (R, error)) *ActionSpec[R]

ActionWithFlags creates a typed custom operation with typed action flags.

func ActionWithFlagsAndContext

func ActionWithFlagsAndContext[R any](name string, flags ActionFlags, fn func(ctx context.Context, id string, flags map[string]string) (R, error)) *ActionSpec[R]

ActionWithFlagsAndContext is ActionWithContext with typed action flags.

func PrimaryActionWithContext added in v1.21.55

func PrimaryActionWithContext[Opts ActionFlags, R any](opts Opts, fn func(context.Context, Opts) (R, error)) *ActionSpec[R]

PrimaryActionWithContext creates the typed collection action that runs when the bare entity command is invoked. Its POST route shares the entity's collection path with the list operation's GET route.

func (*ActionSpec[R]) WithFlags

func (a *ActionSpec[R]) WithFlags(flags ActionFlags) *ActionSpec[R]

func (*ActionSpec[R]) WithMethod

func (a *ActionSpec[R]) WithMethod(method string) *ActionSpec[R]

WithMethod overrides the inferred HTTP method for the generated RPC/OpenAPI action route. Leave empty to keep the default inference behavior.

func (*ActionSpec[R]) WithOptionalID

func (a *ActionSpec[R]) WithOptionalID() *ActionSpec[R]

WithOptionalID makes the positional <id> argument optional on the generated action command. Use for actions whose target is supplied entirely through flags; the `id` passed to the run func is then empty.

func (*ActionSpec[R]) WithShort

func (a *ActionSpec[R]) WithShort(short string) *ActionSpec[R]

func (*ActionSpec[R]) WithToolGroup

func (a *ActionSpec[R]) WithToolGroup(group string) *ActionSpec[R]

WithToolGroup overrides the entity's tool group for this action only. Empty (the default) means the action inherits the entity's group.

func (*ActionSpec[R]) WithToolHints added in v1.21.38

func (a *ActionSpec[R]) WithToolHints(hints MCPToolHints) *ActionSpec[R]

WithToolHints overrides this action's inherited MCP tool hints.

func (*ActionSpec[R]) WithToolPermission added in v1.21.38

func (a *ActionSpec[R]) WithToolPermission(permission ToolPermission) *ActionSpec[R]

WithToolPermission sets this action's default approval mode. Actions carry no verb default: unset defers to the entity's ToolPermission or, failing that, the app's approval policy.

type BulkActionInfo

type BulkActionInfo struct {
	Name              string
	Short             string
	DataFunc          func(flags map[string]string, args []string) (any, error)
	FilterFunc        func(flags map[string]string, args []string) (any, error)
	LookupFunc        func(flags map[string]string, args []string) (any, error)
	ContextLookupFunc ContextLookupFunc
	ListType          reflect.Type
	BindCompletions   func(cmd *cobra.Command)
	ResponseType      reflect.Type
}

BulkActionInfo is the type-erased representation of a bulk action.

type BulkActionSpec

type BulkActionSpec[R any] struct {
	// contains filtered or unexported fields
}

func BulkAction

func BulkAction[R any](name string, fn func(ids []string, flags map[string]string) (R, error)) *BulkActionSpec[R]

BulkAction creates a typed custom operation on multiple entity IDs.

func BulkActionWithFilter

func BulkActionWithFilter[ListOpts any, R any](
	name string,
	run func(ids []string, flags map[string]string) (R, error),
	runFilter func(opts ListOpts, flags map[string]string) (R, error),
) *BulkActionSpec[R]

BulkActionWithFilter creates a typed bulk action that supports both explicit IDs and filtered selections.

func BulkFilterAction

func BulkFilterAction[ListOpts any, R any](name string, fn func(opts ListOpts, flags map[string]string) (R, error)) *BulkActionSpec[R]

BulkFilterAction creates a typed custom operation that runs against a typed filtered list selection instead of explicit IDs.

func (*BulkActionSpec[R]) WithShort

func (b *BulkActionSpec[R]) WithShort(short string) *BulkActionSpec[R]

type ClickyOperationMeta

type ClickyOperationMeta struct {
	SurfaceID          string        `json:"-"`
	Command            string        `json:"command,omitempty"`
	Surface            string        `json:"surface,omitempty"`
	Entity             string        `json:"-"`
	Parent             string        `json:"-"`
	Aliases            []string      `json:"-"`
	Admin              bool          `json:"-"`
	Icon               string        `json:"-"`
	Path               string        `json:"-"`
	Title              string        `json:"-"`
	Verb               string        `json:"verb,omitempty"`
	Scope              string        `json:"scope,omitempty"`
	ActionName         string        `json:"actionName,omitempty"`
	IDParam            string        `json:"idParam,omitempty"`
	SupportsLookup     bool          `json:"supportsLookup,omitempty"`
	SupportsFilterMode bool          `json:"supportsFilterMode,omitempty"`
	Group              string        `json:"group,omitempty"`
	ToolHints          MCPToolHints  `json:"-"`
	OpenAPIToolHints   *MCPToolHints `json:"toolHints,omitempty"`
	Export             *ExportMeta   `json:"export,omitempty"`
	Order              int           `json:"-"`
}

ClickyOperationMeta is emitted as the OpenAPI operation-level x-clicky extension. SurfaceID/Aliases are internal-only fields used while building the final surface list.

type ClickySpecMeta

type ClickySpecMeta struct {
	Surfaces []ClickySurface `json:"surfaces,omitempty"`
}

ClickySpecMeta is emitted as the OpenAPI-level x-clicky extension.

type ClickySurface

type ClickySurface struct {
	Key         string `json:"key"`
	Entity      string `json:"entity"`
	Title       string `json:"title"`
	Parent      string `json:"parent,omitempty"`
	Admin       bool   `json:"admin,omitempty"`
	Description string `json:"description,omitempty"`
	// Icon is an opaque UI icon name (e.g. "database") the frontend resolves to
	// a glyph. Emitted verbatim from the entity's x-clicky-icon annotation.
	Icon string `json:"icon,omitempty"`
	// Path is this surface's position within its Parent group, always separated
	// by PathSeparator (e.g. "jms/incoming/disbursements"). Producers split
	// their own naming convention with SplitPath before emitting it, so the
	// frontend never guesses a delimiter. Empty — the default for every surface
	// that does not opt in — means the group renders as a flat list.
	Path  string `json:"path,omitempty"`
	Order int    `json:"-"`
}

ClickySurface describes a UI surface resolved from clicky entity metadata.

type CommandOpenAPIMeta

type CommandOpenAPIMeta struct {
	Entity  string
	Parent  string
	Aliases []string
	Admin   bool
	// Icon is an opaque UI icon name (e.g. "database"); clicky never interprets
	// it — it is emitted verbatim on the surface for the frontend to resolve.
	Icon string
	// Path is the entity's hierarchy position within Parent, PathSeparator-joined.
	Path string
	// Title overrides the auto-generated surface title when non-empty.
	Title              string
	Verb               string
	Method             string
	Scope              string
	ActionName         string
	IDParam            string
	SupportsLookup     bool
	SupportsFilterMode bool
	// OptionalID is true when the operation's positional id is optional
	// (WithOptionalID). Such operations are invocable without an id, so the
	// generated REST path must NOT carry an {id} segment — otherwise the no-id
	// call collides with the entity's get-by-id route.
	OptionalID bool
	// ToolGroup names the group an operation belongs to. It is set on the entity
	// and inherited by every operation (a per-action override may replace it).
	// AI tool-preference layers use it to enable/disable a set of related tools
	// as one unit.
	ToolGroup string
	ToolHints MCPToolHints
}

CommandOpenAPIMeta is the clicky-specific metadata attached to generated Cobra commands so the RPC/OpenAPI layer can expose entity semantics without guessing from paths or operationIds.

func GetCommandOpenAPIMeta

func GetCommandOpenAPIMeta(cmd *cobra.Command) *CommandOpenAPIMeta

type Config

type Config struct {
	// DefaultMethod is the default HTTP method for operations.
	DefaultMethod string
	// PathPrefix is the path prefix for REST APIs.
	PathPrefix string
	// AutoGeneratePaths controls whether REST paths are generated from the
	// command hierarchy.
	AutoGeneratePaths bool
	// DefaultTags are applied to all operations.
	DefaultTags []string
}

Config holds configuration for RPC conversion.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a sensible default configuration.

type ContextDataFunc

type ContextDataFunc = func(ctx context.Context, flags map[string]string, args []string) (any, error)

ContextDataFunc is the context-aware data closure stored for a command. Its signature matches rpc.ContextDataFunc structurally; the RPC converter converts it when wiring RPCOperation.ContextDataFunc. Defined here (the root package) to avoid a clicky -> clicky/rpc import cycle.

func GetContextDataFunc

func GetContextDataFunc(cmd *cobra.Command) ContextDataFunc

GetContextDataFunc returns the context-aware data function registered for a command, if any. Used by the RPC converter to wire ContextDataFunc.

type ContextFilter

type ContextFilter[ListOpts any] interface {
	OptionsWithContext(ctx context.Context, opts ListOpts) map[string]api.Textable
}

ContextFilter is an OPTIONAL extension a Filter may implement when its option set is resolved from request-scoped state (e.g. a per-request database handle) rather than a process global. When the lookup handler runs with a context (the RPC path feeds r.Context(), the CLI feeds cmd.Context()) it prefers OptionsWithContext over Options; filters that don't implement it fall back to the plain Options() path unchanged.

type ContextLookupFunc

type ContextLookupFunc = func(ctx context.Context, flags map[string]string, args []string) (any, error)

ContextLookupFunc is the context-aware variant of a filter lookup closure. When present, the RPC executor prefers it over LookupFunc and feeds the request's context.Context (r.Context() over HTTP, cmd.Context() on the CLI) so a filter's Options/OptionsWithQuery can resolve request-scoped state (e.g. the per-request database handle) instead of a process global.

func GetContextLookupFunc

func GetContextLookupFunc(cmd *cobra.Command) ContextLookupFunc

GetContextLookupFunc returns the context-aware lookup function registered for a command, if any. Used by the RPC converter to wire ContextLookupFunc.

type ContextSearchableFilter

type ContextSearchableFilter[ListOpts any] interface {
	OptionsWithQueryAndContext(ctx context.Context, opts ListOpts, query string, limit int) (options map[string]api.Textable, total int)
}

ContextSearchableFilter is the context-aware counterpart of SearchableFilter: a large/searchable filter whose head and server-side search both need request-scoped state. The lookup handler prefers it over OptionsWithQuery when a context is available.

type DataFunc

type DataFunc func(flags map[string]string, args []string) (any, error)

DataFunc is a function that returns structured data directly, bypassing stdout capture. Used by commands registered via AddCommand to provide data to the HTTP handler. (ContextDataFunc / ContextLookupFunc — the context-aware variants — are defined alongside the command registry in command.go.)

type DynamicEntityBuilder

type DynamicEntityBuilder struct {
	// contains filtered or unexported fields
}

DynamicEntityBuilder assembles a schema-driven entity and registers it through RegisterDynamicEntity. Filters referenced by x-clicky-filter must be registered (RegisterFilter / RegisterFilterSpec) before Register is called.

func NewDynamicEntity

func NewDynamicEntity(name string, schema []byte) *DynamicEntityBuilder

NewDynamicEntity starts building a dynamic entity from a JSON schema.

func (*DynamicEntityBuilder) Filter added in v1.21.54

func (b *DynamicEntityBuilder) Filter(key, filterName string) *DynamicEntityBuilder

Filter offers the registered filter filterName under key, for an input the rows do not carry — a query parameter, say — and so has no schema property to hang x-clicky-filter on. Schema-declared filters need no such call.

The key is what the request sends and what the lookup response is keyed by. A value supplied for it reaches the filter's source as sibling context even though it is not a declared operation parameter.

func (*DynamicEntityBuilder) Get

func (*DynamicEntityBuilder) List

func (*DynamicEntityBuilder) Register

func (b *DynamicEntityBuilder) Register()

Register parses the schema, generates the runtime types, wires the named filters, and registers the entity. It panics on an invalid schema or an unregistered filter reference — both are setup-time wiring errors.

type DynamicEntityFamily added in v1.21.55

type DynamicEntityFamily struct {
	// Name is the family's path segment: "profile" serves one route,
	// {prefix}/profile/{name}, for every profile that will ever exist.
	Name string

	// Parent groups the family's surfaces, as EntityInfo.Parent does.
	Parent string

	// Resolve returns the spec for one instance. It runs in front of every
	// request to the family, so it has to be cheap enough to sit there. A name
	// that does not exist is UnknownDynamicEntity rather than a zero spec: "no
	// such profile" and "a profile that does nothing" are different answers and a
	// caller has to be able to tell them apart.
	Resolve func(ctx context.Context, name string) (DynamicEntitySpec, error)

	// List enumerates the instances that exist right now, so the OpenAPI document
	// can describe them. It is called per request for the same reason Resolve is:
	// a document rendered once at startup would describe a set that has since
	// changed.
	List func(ctx context.Context) ([]DynamicEntitySpec, error)

	// Paged serves one page or one export of a resolved instance, putting a
	// family instance on the same export contract as RPCOperation.PagedFunc.
	//
	// It hangs off the family rather than off DynamicEntitySpec because the spec
	// says what the entity is and this says how the transport reads it, and
	// because one implementation serves every instance. Nil falls back to the
	// instance's List, served the way every other operation's data is.
	Paged func(ctx context.Context, spec DynamicEntitySpec, req PageRequest, flags map[string]string) (PageResponse, error)
}

DynamicEntityFamily is a route for entities that do not exist yet.

The registry pipeline — entityRegistry, GenerateCLI, Cobra, NewSwaggerServer, RegisterRoutes — is one snapshot taken at startup, so an entity that comes into being while the server runs has no route and no way to acquire one. A consumer whose entities are database rows is locked out of it entirely.

A family registers one route for the whole shape — {prefix}/{Name}/{name} — and resolves the instance per request. Nothing is cached, so an entity created a moment ago is immediately reachable and none of the startup pipeline has to be re-run or invalidated.

func GetDynamicEntityFamilies added in v1.21.55

func GetDynamicEntityFamilies() []DynamicEntityFamily

GetDynamicEntityFamilies returns the registered families.

Nil when none are registered, rather than an empty slice: this is consulted on the way into every executor request, and a consumer that registers no family must not pay an allocation for the feature it does not use.

type DynamicEntitySpec

type DynamicEntitySpec struct {
	Name    string
	Parent  string
	Aliases []string
	// Icon is an opaque UI icon name emitted on the surface (x-clicky.surfaces[].icon).
	Icon string
	// Path is the hierarchy position emitted on the surface (x-clicky.surfaces[].path).
	Path string
	// Title overrides the auto-generated surface title when non-empty.
	Title    string
	ListType reflect.Type // generated struct type: flag binding + OpenAPI params
	ItemType reflect.Type // generated item struct type for the response schema
	List     ContextDataFunc
	Get      ContextDataFunc
	Filters  []DynamicFilter
	// FilterRefs maps a filter key to the reusable named filter backing it, so
	// the OpenAPI layer can emit an x-clicky-lookup $ref (see EntityInfo.FilterRefs).
	FilterRefs map[string]string
}

DynamicEntitySpec is the type-erased description of a schema-driven entity, assembled by the entity package's NewDynamicEntity builder. It reuses the existing pipeline: ListType drives CLI flag binding and OpenAPI parameters, ItemType drives the response schema, and Filters feed the shared lookup engine.

type DynamicFilter

type DynamicFilter struct {
	Key        string
	Label      string
	Type       string
	Multi      bool
	Searchable bool
	// Limit caps the option set this filter enumerates in one shot. Zero takes
	// MaxLookupOptions, which is also the ceiling.
	Limit int
	// Options returns the head set (query == "") or search matches, plus the true
	// total behind the head. Required.
	Options func(ctx context.Context, flags map[string]string, query string, limit int) (map[string]api.Textable, int, error)
	// Selected labels the currently-selected value(s) of this filter's key.
	// Optional; nil means "no selection rendering".
	Selected func(ctx context.Context, flags map[string]string) (map[string]api.Textable, error)
}

DynamicFilter describes one filter on a dynamic (schema-driven) entity. The Options/Selected closures resolve from the request flag map — they are built by the entity package from a reusable named filter — so the type-agnostic filter logic stays out of this package while reusing the shared lookup builder.

type DynamicGetFunc

type DynamicGetFunc func(ctx context.Context, id string) (map[string]any, error)

DynamicGetFunc fetches a single dynamic-entity row by id.

type DynamicListFunc

type DynamicListFunc func(ctx context.Context, opts map[string]string) ([]map[string]any, error)

DynamicListFunc lists rows of a dynamic entity for the given flag map.

type Entity

type Entity[T EntityItem, ListOpts any, R any] struct {
	Name string
	// Parent, when set, nests the entity's command under a parent cobra command
	// with that name. The parent command is created lazily by GenerateCLI if it
	// does not already exist.
	Parent string
	// Aliases applied to the generated entity cobra command.
	Aliases []string
	// Path is the entity's hierarchy position within Parent, PathSeparator-joined
	// (x-clicky.surfaces[].path). Build it with JoinPath/SplitPath so the
	// separator stays the wire convention. Empty declares no hierarchy.
	Path string
	List func(opts ListOpts) ([]T, error)
	Get  func(id string) (R, error)
	// ListWithContext / GetWithContext / GetWithFlagsAndContext are context-aware
	// variants of List / Get / GetWithFlags. When set they take precedence over
	// their non-context counterparts and receive the request-scoped
	// context.Context (r.Context() over HTTP, cmd.Context() on the CLI). Use them
	// to resolve per-request state (e.g. a database/config bundle) instead of
	// reaching for process globals.
	ListWithContext        func(ctx context.Context, opts ListOpts) ([]T, error)
	ListPaged              func(opts ListOpts) (PagedResult[T], error)
	ListPagedWithContext   func(ctx context.Context, opts ListOpts) (PagedResult[T], error)
	GetWithContext         func(ctx context.Context, id string) (R, error)
	GetWithFlagsAndContext func(ctx context.Context, id string, flags map[string]string) (R, error)
	// GetFlags, when non-nil, is a zero-value struct value implementing
	// ActionFlags whose `flag:"..."` tagged fields are registered as
	// CLI flags on the generated `get` subcommand. The parsed values are
	// passed into GetWithFlags.
	//
	// GetWithFlags is mutually exclusive with Get: when both are set,
	// GetWithFlags wins. Set GetFlags to declare the flag schema and
	// GetWithFlags to receive the typed values.
	GetFlags     ActionFlags
	GetWithFlags func(id string, flags map[string]string) (R, error)
	Create       func(body map[string]any) (R, error)
	Update       func(id string, body map[string]any) (R, error)
	Delete       func(id string) error
	// CreateWithContext / UpdateWithContext / DeleteWithContext are context-aware
	// variants of Create / Update / Delete, mirroring the read-side seam above.
	// When set they take precedence and receive the request-scoped context, so
	// writes target the request's environment rather than a process global.
	CreateWithContext func(ctx context.Context, body map[string]any) (R, error)
	UpdateWithContext func(ctx context.Context, id string, body map[string]any) (R, error)
	DeleteWithContext func(ctx context.Context, id string) error
	Filters           []Filter[ListOpts]

	PrimaryAction EntityAction
	Actions       []EntityAction
	BulkActions   []EntityBulkAction

	// Admin groups admin-only operations (inspect, configure, etc.)
	// that produce different views/columns from the main CRUD operations.
	// Generates subcommands under an "admin" subgroup and routes like /entity/admin/{verb}.
	Admin *Entity[T, ListOpts, R]

	// ValidArgs provides shell completion for the ID argument.
	ValidArgs func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)

	// ToolGroup names the group all of this entity's operations belong to. It is
	// inherited by every generated operation; an action may override it via
	// WithToolGroup. AI tool-preference layers use it to toggle related tools
	// together.
	ToolGroup string
	ToolHints MCPToolHints
}

Entity configures a CRUD resource. All function fields are optional. T is the type returned by List and must implement EntityItem. R is the type returned by Get/Create/Update.

type EntityAction

type EntityAction interface {
	// contains filtered or unexported methods
}

EntityAction is the type-erased registration surface for custom entity actions. Use Action or ActionWithFlags to construct values.

type EntityBuilder

type EntityBuilder[T EntityItem, ListOpts any, R any] struct {
	// contains filtered or unexported fields
}

EntityBuilder provides a fluent API for registering typed entities.

func NewEntity

func NewEntity[T EntityItem, ListOpts any, R any](name string) *EntityBuilder[T, ListOpts, R]

NewEntity starts a typed entity registration. The resulting entity is served identically on the CLI and over HTTP/RPC. See the package github.com/flanksource/clicky/entity for an authoring guide, the best practices for operations that behave well on both surfaces, and runnable examples.

func (*EntityBuilder[T, ListOpts, R]) Admin

func (b *EntityBuilder[T, ListOpts, R]) Admin(admin Entity[T, ListOpts, R]) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) Aliases

func (b *EntityBuilder[T, ListOpts, R]) Aliases(aliases ...string) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) Build

func (b *EntityBuilder[T, ListOpts, R]) Build() Entity[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) Create

func (b *EntityBuilder[T, ListOpts, R]) Create(fn func(map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) CreateWithContext

func (b *EntityBuilder[T, ListOpts, R]) CreateWithContext(fn func(context.Context, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]

CreateWithContext sets the context-aware create handler. The context carries request-scoped state (e.g. the originating *http.Request via rpc.RequestFromContext), letting handlers read the raw nested JSON body the executor would otherwise flatten to string flags.

func (*EntityBuilder[T, ListOpts, R]) Delete

func (b *EntityBuilder[T, ListOpts, R]) Delete(fn func(string) error) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) DeleteWithContext

func (b *EntityBuilder[T, ListOpts, R]) DeleteWithContext(fn func(context.Context, string) error) *EntityBuilder[T, ListOpts, R]

DeleteWithContext sets the context-aware delete handler. See CreateWithContext.

func (*EntityBuilder[T, ListOpts, R]) Filters

func (b *EntityBuilder[T, ListOpts, R]) Filters(filters ...Filter[ListOpts]) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) Get

func (b *EntityBuilder[T, ListOpts, R]) Get(fn func(string) (R, error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) GetWithContext

func (b *EntityBuilder[T, ListOpts, R]) GetWithContext(fn func(context.Context, string) (R, error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) GetWithFlags

func (b *EntityBuilder[T, ListOpts, R]) GetWithFlags(flags ActionFlags, fn func(string, map[string]string) (R, error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) GetWithFlagsAndContext added in v1.21.52

func (b *EntityBuilder[T, ListOpts, R]) GetWithFlagsAndContext(flags ActionFlags, fn func(context.Context, string, map[string]string) (R, error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) List

func (b *EntityBuilder[T, ListOpts, R]) List(fn func(ListOpts) ([]T, error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) ListPaged

func (b *EntityBuilder[T, ListOpts, R]) ListPaged(fn func(ListOpts) (PagedResult[T], error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) ListPagedWithContext

func (b *EntityBuilder[T, ListOpts, R]) ListPagedWithContext(fn func(context.Context, ListOpts) (PagedResult[T], error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) ListWithContext

func (b *EntityBuilder[T, ListOpts, R]) ListWithContext(fn func(context.Context, ListOpts) ([]T, error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) Parent

func (b *EntityBuilder[T, ListOpts, R]) Parent(parent string) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) Path added in v1.21.55

func (b *EntityBuilder[T, ListOpts, R]) Path(segments ...string) *EntityBuilder[T, ListOpts, R]

Path sets the entity's hierarchy position within its parent, joined by PathSeparator, and surfaced as x-clicky.surfaces[].path. Pass segments through JoinPath rather than concatenating them by hand.

func (*EntityBuilder[T, ListOpts, R]) Register

func (b *EntityBuilder[T, ListOpts, R]) Register()

func (*EntityBuilder[T, ListOpts, R]) ToolGroup

func (b *EntityBuilder[T, ListOpts, R]) ToolGroup(group string) *EntityBuilder[T, ListOpts, R]

ToolGroup names the group this entity's operations belong to. Every generated operation inherits it (an action can override it via WithToolGroup). AI tool-preference layers use the group to enable/disable related tools together.

func (*EntityBuilder[T, ListOpts, R]) ToolHints added in v1.21.38

func (b *EntityBuilder[T, ListOpts, R]) ToolHints(hints MCPToolHints) *EntityBuilder[T, ListOpts, R]

ToolHints sets MCP-facing annotations and Clicky UI metadata inherited by all generated operations. Per-action hints can override these values.

func (*EntityBuilder[T, ListOpts, R]) ToolPermission added in v1.21.38

func (b *EntityBuilder[T, ListOpts, R]) ToolPermission(permission ToolPermission) *EntityBuilder[T, ListOpts, R]

ToolPermission sets the default approval mode inherited by every generated operation, replacing the standard verb defaults (list/get auto-run, create/update/delete ask). A per-action WithToolPermission overrides it.

func (*EntityBuilder[T, ListOpts, R]) Update

func (b *EntityBuilder[T, ListOpts, R]) Update(fn func(string, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) UpdateWithContext

func (b *EntityBuilder[T, ListOpts, R]) UpdateWithContext(fn func(context.Context, string, map[string]any) (R, error)) *EntityBuilder[T, ListOpts, R]

UpdateWithContext sets the context-aware update handler. See CreateWithContext.

func (*EntityBuilder[T, ListOpts, R]) ValidArgs

func (b *EntityBuilder[T, ListOpts, R]) ValidArgs(fn func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective)) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) WithAction

func (b *EntityBuilder[T, ListOpts, R]) WithAction(action EntityAction) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) WithBulkAction

func (b *EntityBuilder[T, ListOpts, R]) WithBulkAction(action EntityBulkAction) *EntityBuilder[T, ListOpts, R]

func (*EntityBuilder[T, ListOpts, R]) WithPrimaryAction added in v1.21.55

func (b *EntityBuilder[T, ListOpts, R]) WithPrimaryAction(action EntityAction) *EntityBuilder[T, ListOpts, R]

type EntityBulkAction

type EntityBulkAction interface {
	// contains filtered or unexported methods
}

EntityBulkAction is the type-erased registration surface for custom bulk actions. Use BulkAction or BulkFilterAction to construct values.

type EntityInfo

type EntityInfo struct {
	Name    string
	Parent  string
	Aliases []string
	// Icon is an opaque UI icon name carried through to the OpenAPI surface
	// (x-clicky.surfaces[].icon). Empty for entities that declare no icon.
	Icon string
	// Path is the entity's hierarchy position within Parent, PathSeparator-joined
	// (x-clicky.surfaces[].path). Empty for entities that declare no hierarchy.
	Path string
	// Title overrides the auto-generated surface title when non-empty.
	Title         string
	Type          reflect.Type
	ListType      reflect.Type
	Operations    []EntityOperation
	PrimaryAction *ActionInfo
	Actions       []ActionInfo
	BulkActions   []BulkActionInfo
	ValidArgs     func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective)
	IsAdmin       bool
	// FilterRefs maps a list filter's flag key to the name of the reusable named
	// filter backing it (when the filter was attached via the entity package's
	// Use/As helper). The OpenAPI layer uses it to emit an x-clicky-lookup $ref
	// to the shared filter definition. Nil when no filters reference a named one.
	FilterRefs map[string]string
	// ToolGroup names the group all of this entity's operations belong to. It is
	// inherited by every generated operation (an action may override it) and is
	// used by AI tool-preference layers to toggle related tools together.
	ToolGroup string
	ToolHints MCPToolHints
}

EntityInfo is the type-erased representation stored in the registry.

func GetEntities

func GetEntities() []EntityInfo

GetEntities returns all registered entities.

func GetEntity

func GetEntity(name string) (EntityInfo, bool)

GetEntity returns the registered entity with the given name (or alias) and whether it was found.

type EntityItem

type EntityItem interface {
	GetID() string
	GetName() string
}

EntityItem is the interface that all entity types must implement.

type EntityOperation

type EntityOperation struct {
	Verb     string // "list", "get", "create", "update", "delete"
	Method   string // Optional explicit HTTP method for generated RPC/OpenAPI routes.
	DataFunc func(flags map[string]string, args []string) (any, error)
	// ContextDataFunc, when set, is preferred over DataFunc by both the CLI run
	// path (fed cmd.Context()) and the RPC executor (fed r.Context()). Lets the
	// operation resolve request-scoped state instead of process globals.
	ContextDataFunc ContextDataFunc
	// FlagsType, when non-nil, binds typed flags from the given struct type
	// onto the generated cobra command and collects their values into the
	// flag map passed to DataFunc. Used by actions that implement
	// ActionFlags; ignored for the built-in CRUD verbs.
	FlagsType  reflect.Type
	LookupFunc func(flags map[string]string, args []string) (any, error)
	// ContextLookupFunc, when set, is the context-aware filter lookup closure.
	// The RPC converter wires it onto RPCOperation.ContextLookupFunc and the
	// executor prefers it over LookupFunc, feeding the request context.
	ContextLookupFunc ContextLookupFunc
	BindCompletions   func(cmd *cobra.Command)
	ResponseType      reflect.Type
	ResponseArray     bool
	ResponsePaged     bool
	ResponseEntityID  bool
}

EntityOperation represents a single CRUD operation.

type ExecutableCommand

type ExecutableCommand interface {
	// Execute runs the command with the given options, capturing everything
	// written to os.Stdout / os.Stderr (including direct writes, not just the
	// cobra writers). It is safe for concurrent callers: implementations that
	// swap process-global file descriptors serialize internally.
	Execute(ctx context.Context, opts ExecuteOptions) (stdout, stderr string, err error)

	// Path is the full space-joined command path ("user create").
	Path() string
	// Name is the leaf command name ("create").
	Name() string
	// RootName is the top-level application command name ("xero-cli"), used for
	// the MCP tool title.
	RootName() string

	// Runnable reports whether the command has a Run/RunE (not a pure group).
	Runnable() bool
	// Hidden reports whether the command is hidden from help/listing.
	Hidden() bool

	// IsBoolFlag reports whether the named flag is a boolean flag. Used by the
	// CLI-string reconstruction to render "--flag" vs "--flag=value".
	IsBoolFlag(name string) bool
}

ExecutableCommand is the transport-neutral handle an RPCOperation holds onto in place of a concrete *cobra.Command. It encapsulates everything the execution path (RPC executor, MCP server) and the tool-surfacing layers (aichat) need, so those packages no longer reference cobra directly.

The cobra-specific machinery — the global os.Stdout/os.Stderr pipe swap, flag copying, state reset — lives entirely inside the CobraExecutableCommand implementation (rpc package).

type ExecuteOptions

type ExecuteOptions struct {
	// Args are the positional arguments.
	Args []string
	// Flags maps flag name -> string value. A flag absent on the command is
	// silently skipped (path params and other non-flag keys may appear here);
	// a present flag whose value fails to parse returns an error.
	Flags map[string]string
	// FormatOverrides are best-effort flag values applied before execution
	// (e.g. {"format":"markdown","no-color":"true"}). A flag absent on the
	// command is silently skipped. Used by the MCP server's format forcing.
	FormatOverrides map[string]string
}

ExecuteOptions controls how an ExecutableCommand runs one invocation. It is the transport-neutral subset of what the RPC executor and MCP server previously poked directly onto a *cobra.Command.

type ExportHeaderDoc added in v1.21.55

type ExportHeaderDoc struct {
	Description string
	Type        string
}

ExportHeaderDoc documents one response header for the OpenAPI spec. It is deliberately not the rpc package's own header type: rpc imports entity, so the description travels as plain data and rpc adapts it.

type ExportMeta added in v1.21.38

type ExportMeta struct {
	Formats       []string       `json:"formats,omitempty"`
	Scopes        []string       `json:"scopes,omitempty"`
	AllRowsMode   string         `json:"allRowsMode,omitempty"`
	FormatMaxRows map[string]int `json:"formatMaxRows,omitempty"`
}

ExportMeta advertises the representations and scopes an operation can download. UI consumers preserve legacy download behavior when this metadata is absent.

type Filter

type Filter[ListOpts any] interface {
	Key() string
	Label() string
	Lookup(opts *ListOpts) (map[string]api.Textable, error)
	Options(opts ListOpts) map[string]api.Textable
}

Filter resolves raw entity option values into the backend-specific shape and exposes UI metadata for the currently selected and available values.

func LiftFilters

func LiftFilters[Outer any, Inner any](
	filters []Filter[Inner],
	project func(*Outer) *Inner,
) []Filter[Outer]

LiftFilters adapts a Filter[Inner] slice so the same picker definitions work against an outer struct that embeds (or otherwise reaches) the inner filter struct. The project func extracts a *Inner from any *Outer the filter system hands us; lookup keys, labels, options, and selected-value reads/writes flow through unchanged. Use this to keep picker constructors scoped to the inner filter type while letting subcommand options structs — which also carry positional args, behaviour flags, etc. — satisfy Filterable[Outer].

type FilterContext

type FilterContext struct {
	// Context is the request context (HTTP request or CLI command). It may be
	// nil when a source is invoked outside a request (e.g. shell completion).
	Context context.Context
	// Key is the bound flag/field name this filter resolves on the current
	// entity (e.g. "owner" when a "users" filter is attached via .As("owner")).
	Key string
	// Params holds the current values of every flag/filter on the entity, so a
	// source can narrow its options against sibling selections (cascading).
	Params map[string]string
}

FilterContext carries the request-scoped state a FilterSource needs to resolve its options. It is the single representation both static and dynamic entities can produce: a static entity reflects its typed ListOpts into Params, a dynamic entity already holds the flag map.

func (FilterContext) Ctx

func (fc FilterContext) Ctx() context.Context

Ctx returns the context, defaulting to context.Background when none was set.

type FilterSource

type FilterSource interface {
	// Options returns the available options, optionally narrowed by query, and
	// the true total count behind the (possibly capped) returned set. An empty
	// query means "the head set". A non-positive limit means "no cap".
	Options(fc FilterContext, query string, limit int) (options map[string]api.Textable, total int, err error)
	// Resolve labels the currently-selected raw value(s) for display. A value
	// with no known label is echoed back as plain text.
	Resolve(fc FilterContext, values []string) (map[string]api.Textable, error)
}

FilterSource produces the options for a NamedFilter. Implementations are type-agnostic — they read FilterContext.Params rather than a typed struct — so one source serves any entity that references the filter.

func EntityOptions

func EntityOptions(entityName string) FilterSource

EntityOptions is a FilterSource that resolves its options from another registered entity: value = GetID(), label = PrettyShort()/GetName(). Search is an in-memory substring match over the source entity's list.

func FuncOptions

func FuncOptions(fn func(fc FilterContext, query string, limit int) (map[string]api.Textable, int, error)) FilterSource

FuncOptions is a FilterSource backed by a user-supplied function — the general escape hatch for DB-backed or computed options with server-side search. The function owns query matching and the limit cap.

func StaticOptions

func StaticOptions(options map[string]api.Textable) FilterSource

StaticOptions is a FilterSource backed by a fixed set of options, narrowed by case-insensitive substring match on the option key or its rendered label.

type FilterSourceSpec

type FilterSourceSpec struct {
	Kind string `json:"kind" yaml:"kind"`
	// Options is the value→label map for a static source.
	Options map[string]string `json:"options,omitempty" yaml:"options,omitempty"`
	// Entity is the source entity name for an entity source.
	Entity string `json:"entity,omitempty" yaml:"entity,omitempty"`
}

FilterSourceSpec is the declarative description of where a filter's options come from. "static" and "entity" are constructible from a spec; "func" is Go-only and only ever appears on the emit side (NamedFilter.Spec).

type FilterSpec

type FilterSpec struct {
	Name   string           `json:"name" yaml:"name"`
	Label  string           `json:"label,omitempty" yaml:"label,omitempty"`
	Type   string           `json:"type,omitempty" yaml:"type,omitempty"`
	Multi  bool             `json:"multi,omitempty" yaml:"multi,omitempty"`
	Source FilterSourceSpec `json:"source" yaml:"source"`
}

FilterSpec is the JSON/YAML-authorable form of a NamedFilter. It is also the shape emitted for OpenAPI (NamedFilter.Spec), so a Go-defined filter and a declaratively-defined one are indistinguishable to clients.

type Filterable

type Filterable[T any] interface {
	Filters() []Filter[T]
}

Filterable is implemented by AddNamedCommand options structs that want to expose typed filter lookups (dropdowns/typeaheads on the web UI, shell completions on the CLI) on the subcommand itself rather than inheriting only the parent entity's Filters slice. The same Filter[T] values that back an Entity's Filters slice work here; AddNamedCommand stores a LookupFunc in the lookupFuncRegistry and binds completions whenever an opts struct satisfies this interface.

Use this whenever a subcommand's flag surface diverges from its parent list view — typically when a positional argument pins one or more identifier filters and the subcommand only exposes the orthogonal (status, type, date range) lenses.

type Help

type Help interface {
	Help() api.Textable
}

Help is implemented by options structs that supply their own long-form command help. The generated command sets cmd.Long from Help().ANSI().

type LimitedFilter added in v1.21.55

type LimitedFilter interface {
	// LookupLimit returns the head/search cap, or zero to take the default.
	LookupLimit() int
}

LimitedFilter is an OPTIONAL extension a Filter may implement to cap its own option set below the package ceiling. It is unparameterized because the cap is a property of the filter's cardinality, not of the entity it is attached to.

type MCPToolHints added in v1.21.38

type MCPToolHints struct {
	Title             string         `json:"title,omitempty"`
	ReadOnlyHint      *bool          `json:"readOnlyHint,omitempty"`
	DestructiveHint   *bool          `json:"destructiveHint,omitempty"`
	IdempotentHint    *bool          `json:"idempotentHint,omitempty"`
	OpenWorldHint     *bool          `json:"openWorldHint,omitempty"`
	Icon              string         `json:"icon,omitempty"`
	Group             string         `json:"group,omitempty"`
	Parent            string         `json:"parent,omitempty"`
	DefaultPermission ToolPermission `json:"defaultPermission,omitempty"`
	Strict            *bool          `json:"strict,omitempty"`
}

MCPToolHints describes MCP tool annotations plus Clicky-specific UI and approval metadata. Boolean fields are pointers because both true and false are meaningful MCP hint values.

func (MCPToolHints) IsZero added in v1.21.38

func (h MCPToolHints) IsZero() bool

IsZero reports whether no tool metadata or MCP annotations are set.

type MultiFilter

type MultiFilter []string

MultiFilter is a string-list flag whose values are interpreted with collections.MatchItems semantics: plain values include, !value excludes.

type Name

type Name interface {
	GetName() string
}

type NamedFilter

type NamedFilter struct {
	// Name is the unique registry key.
	Name string
	// Label is the human-facing control label. Defaults to Name when empty.
	Label string
	// Type is the UI control type: "select" (default), "multi-select", "date",
	// "from", or "to".
	Type string
	// Multi reports whether the control accepts multiple selections.
	Multi bool
	// Limit caps the option set this filter enumerates in one shot. Zero takes
	// MaxLookupOptions, which is also the ceiling. Declare a smaller one for a
	// field whose cardinality makes a full head set useless to pick from: what
	// is past it is reached by typing, not by scrolling.
	Limit int
	// Source resolves the filter's options.
	Source FilterSource
}

NamedFilter is a reusable filter definition registered under a unique name and attached to entities by reference. Authored in Go (RegisterFilter) or declaratively (RegisterFilterSpec), both normalize to this type.

func FilterFromSpec

func FilterFromSpec(s FilterSpec) (NamedFilter, error)

FilterFromSpec builds (but does not register) a NamedFilter from a declarative spec, validating the source kind.

func GetFilter

func GetFilter(name string) (NamedFilter, bool)

GetFilter returns the named filter and whether it was found.

func MustGetFilter

func MustGetFilter(name string) NamedFilter

MustGetFilter returns the named filter, panicking if it is not registered. Used at attach time (Use/.As), where an unknown reference is a wiring bug.

func (NamedFilter) Spec

func (f NamedFilter) Spec() FilterSpec

Spec emits the declarative form of a NamedFilter, used for OpenAPI generation and round-tripping. A func/custom source emits its kind without detail (its options are resolved server-side via the lookup endpoint).

type PageInfo

type PageInfo struct {
	Limit  int   `json:"limit"`
	Offset int   `json:"offset"`
	Total  int64 `json:"total"`
}

PageInfo carries the effective paging window for a list response.

type PageLimits added in v1.21.55

type PageLimits struct {
	DefaultPageSize int
	MaxPageSize     int
}

PageLimits bound what one request may ask for. A zero value resolves to the defaults, so a caller with no opinion does not have to state one.

type PageRequest added in v1.21.55

type PageRequest struct {
	// Scope is ScopePage or ScopeAll.
	Scope string
	// Format is the resolved export format, after ?format and Accept have been
	// reconciled — the operation never has to look at either again.
	Format string
	// Cursor is an opaque position handed back by a previous page.
	Cursor string
	// Filename overrides the download name. Empty means derive one.
	Filename string

	Limit  int
	Offset int

	// Download asks for a Content-Disposition even when no filename was named.
	Download bool

	// SkipTotal waives the exact total. A backend asked for the size of the whole
	// result has to produce the whole result first, which is the difference
	// between an export that streams and one that hangs until the last row is
	// found — so an all-rows export declines to ask.
	SkipTotal bool
}

PageRequest is one export: which rows, in what shape, and how far.

func ParsePageRequest added in v1.21.55

func ParsePageRequest(r *http.Request, limits PageLimits) (PageRequest, error)

ParsePageRequest reads the transport half of a request: which rows, in what shape, and how far. Every failure is a StatusError so the caller writes one error shape rather than choosing between two.

type PageResponse added in v1.21.55

type PageResponse struct {
	Rows formatters.RowIterator

	// Mode is ModePage, ModeBuffered or ModeStreaming.
	Mode string

	// Total is nil when the backend states no size for the whole result.
	Total   *Total
	HasMore bool
	// Next is the opaque position resuming after this page, when the provider
	// issued one.
	Next string

	// Ceiling stops an all-rows export. Zero means the rows are already bounded,
	// and therefore that nothing is left to discover by reading to the end.
	Ceiling int

	// MaxRows is the ceiling this export was bounded by, reported so a caller
	// sees the same number the server enforced.
	MaxRows int

	// Truncated reports a cut this response already knows about — the operation's
	// own size, or a cap the backend applied. A ceiling is not known to have
	// bitten until the rows have been read, so that case is reported as a trailer.
	Truncated bool

	// Pageable reports whether the operation can serve a position past its first
	// page. A response that cannot must not report one as available.
	Pageable bool
}

PageResponse is everything the transport reports about the rows it is about to write. Every field is resolved before the first byte of the body, because a header cannot be corrected once the body has begun.

It is unrelated to PagedResult[T], the buffered JSON envelope: this one is what clicky turns into an HTTP response, and its rows are still unread.

type Paged

type Paged interface {
	PageMetadata() PageInfo
	PageRows() any
}

Paged is implemented by list results that carry total-count metadata.

type PagedFunc added in v1.21.55

type PagedFunc func(ctx context.Context, req PageRequest, flags map[string]string) (PageResponse, error)

PagedFunc supplies one page or one export of rows.

It is preferred over ContextDataFunc when set, and the division is the point: the operation answers only what the rows are and what is true about them — how many exist, whether more can be asked for, where to resume — while clicky owns the response. Content negotiation, every header below, streaming and the download name are therefore identical across every operation that opts in, rather than re-derived per command.

type PagedResult

type PagedResult[T any] struct {
	Data []T      `json:"data"`
	Page PageInfo `json:"page"`
}

PagedResult is a typed list response with paging metadata.

func NewPagedResult

func NewPagedResult[T any](rows []T, limit, offset int, total int64) PagedResult[T]

NewPagedResult returns a paged result with a stable non-nil data array.

func (PagedResult[T]) PageMetadata

func (p PagedResult[T]) PageMetadata() PageInfo

func (PagedResult[T]) PageRows

func (p PagedResult[T]) PageRows() any

type Property

type Property struct {
	Type        string      `json:"type"`
	Description string      `json:"description"`
	Enum        []string    `json:"enum,omitempty"`
	Default     interface{} `json:"default,omitempty"`
}

Property represents a JSON schema property.

type RPCOperation

type RPCOperation struct {
	Name              string               `json:"name"`
	Description       string               `json:"description"`
	Parameters        []RPCParameter       `json:"parameters"`
	Schema            Schema               `json:"schema"`
	Command           ExecutableCommand    `json:"-"`                // Transport-neutral handle to the original command
	Path              string               `json:"path,omitempty"`   // For REST APIs
	Method            string               `json:"method,omitempty"` // HTTP method
	Tags              []string             `json:"tags,omitempty"`   // OpenAPI tags (auto-derived from the parent command)
	Group             string               `json:"group,omitempty"`  // tool-group this operation belongs to (clicky/tool-group)
	ToolHints         MCPToolHints         `json:"-"`                // MCP annotations and Clicky-specific tool metadata
	DataFunc          DataFunc             `json:"-"`                // Direct data provider, bypasses stdout capture
	ContextDataFunc   ContextDataFunc      `json:"-"`                // Context-aware data provider; preferred over DataFunc when set
	PagedFunc         PagedFunc            `json:"-"`                // Paging/export data provider returning a PageResponse; preferred over ContextDataFunc when set. The operation supplies rows and the paging facts about them, and clicky owns the response: headers, content negotiation, streaming and the download name.
	LookupFunc        DataFunc             `json:"-"`                // Direct filter metadata provider
	ContextLookupFunc ContextLookupFunc    `json:"-"`                // Context-aware filter metadata provider; preferred over LookupFunc when set
	Clicky            *ClickyOperationMeta `json:"-"`                // Entity semantics used for OpenAPI extensions
	ResponseType      reflect.Type         `json:"-"`                // Static response type for OpenAPI generation
	ResponseArray     bool                 `json:"-"`                // Response body is an array of ResponseType
	ResponsePaged     bool                 `json:"-"`                // Response body is a paged envelope around ResponseType rows
	ResponseEntityID  bool                 `json:"-"`                // Array item schema should include Clicky _id metadata
}

RPCOperation represents a generic RPC operation that can be converted to various formats (OpenAPI, MCP tools, …).

type RPCParameter

type RPCParameter struct {
	Name        string      `json:"name"`
	Type        string      `json:"type"`
	Description string      `json:"description"`
	Required    bool        `json:"required"`
	Default     interface{} `json:"default,omitempty"`
	In          string      `json:"in,omitempty"` // "query", "path", "header" for REST
}

RPCParameter represents a parameter in an RPC operation.

type RPCService

type RPCService struct {
	Name        string         `json:"name"`
	Version     string         `json:"version"`
	Description string         `json:"description"`
	Operations  []RPCOperation `json:"operations"`
}

RPCService represents a collection of RPC operations.

type ResponseOpenAPIMeta

type ResponseOpenAPIMeta struct {
	Type     reflect.Type
	Array    bool
	Paged    bool
	EntityID bool
}

ResponseOpenAPIMeta describes the static response type for a generated command. It is consumed by the RPC/OpenAPI layer without executing handlers.

func GetCommandResponseMeta

func GetCommandResponseMeta(cmd *cobra.Command) *ResponseOpenAPIMeta

GetCommandResponseMeta returns static response metadata attached to a command.

type Schema

type Schema struct {
	Type       string              `json:"type"`
	Properties map[string]Property `json:"properties"`
	Required   []string            `json:"required"`
}

Schema represents a JSON schema for operation input/output.

type SearchableFilter

type SearchableFilter[ListOpts any] interface {
	OptionsWithQuery(opts ListOpts, query string, limit int) (options map[string]api.Textable, total int)
}

SearchableFilter is an OPTIONAL extension a Filter may implement when its option set is too large to enumerate in one shot (e.g. a SQL DISTINCT column with thousands of values). The lookup handler type-asserts to it; filters that don't implement it keep the plain Options() behaviour unchanged.

OptionsWithQuery returns at most limit options. An empty query means "the head set": the first limit options plus total = the true distinct count, so the UI can show "… and N more". A non-empty query returns up to limit options matching it (server-side search), letting the UI surface values that sort beyond the head. total is only meaningful for the head (query == "") call.

type StatusError added in v1.21.55

type StatusError struct {
	// Status is the HTTP status this error is written with. It never appears in
	// the body: the status line already carries it, and repeating it invites the
	// two to disagree.
	Status int `json:"-"`

	Code    string `json:"code"`
	Message string `json:"message"`
}

StatusError is the body every failed HTTP operation returns.

The 409 that asks for a connection has always been structured, and a client that can branch on one code but has to string-match the rest is a client that breaks when a message is reworded. Code is the stable part; Message is for a person to read. It replaces http.Error, whose flat text body forces exactly the string-matching this exists to avoid.

func NewStatusError added in v1.21.55

func NewStatusError(status int, code, message string) *StatusError

NewStatusError builds an error a handler can return and the transport can write verbatim.

func NewStatusErrorf added in v1.21.55

func NewStatusErrorf(status int, code, format string, args ...any) *StatusError

NewStatusErrorf is NewStatusError with a formatted message.

func UnknownDynamicEntity added in v1.21.55

func UnknownDynamicEntity(family, name string) *StatusError

UnknownDynamicEntity is the answer to a name a family cannot resolve.

func (*StatusError) Error added in v1.21.55

func (e *StatusError) Error() string

func (*StatusError) StatusCode added in v1.21.55

func (e *StatusError) StatusCode() int

StatusCode reports the status this error should be written with, defaulting to 500 so a zero Status can never produce an invalid status line.

func (*StatusError) Write added in v1.21.55

func (e *StatusError) Write(w http.ResponseWriter)

Write renders the error as its JSON body at its status.

type ToolPermission added in v1.21.38

type ToolPermission string

ToolPermission is the default approval mode a tool advertises to clients.

const (
	ToolPermissionAsk  ToolPermission = "ask"
	ToolPermissionOff  ToolPermission = "off"
	ToolPermissionOn   ToolPermission = "on"
	ToolPermissionAuto ToolPermission = "auto"
)

type Total added in v1.21.55

type Total struct {
	Value int64
	Exact bool
}

Total is a result-set size together with how much the backend was willing to promise about it.

func (*Total) Relation added in v1.21.55

func (t *Total) Relation() string

Relation reports how X-Total-Count should be read.

A nil Total is the third answer and the reason this is a pointer method: a backend that states no total at all is different from one that reports zero, and without a relation those two are the same absent header.

type TypedFilter

type TypedFilter[ListOpts any] interface {
	LookupType() string
}

TypedFilter is an OPTIONAL extension a Filter may implement when the underlying flag type is intentionally broader than the UI control type. For example, date-math flags often remain strings at the CLI layer while the web lookup response should still advertise a from/to date-range control.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL