Documentation
¶
Overview ¶
Package search is the unified search service: a SQLite FTS5 index fed by providers, filtered through an Authorizer before any hit leaves it.
Index ¶
- Constants
- Variables
- type ActionDef
- type ActionInfo
- type ActionsProvider
- type Authorizer
- type Caller
- type DB
- type Doc
- type Hit
- type Kind
- type Provider
- type Query
- type Request
- type Response
- type Saved
- type Scope
- type Service
- func (s *Service) DeleteSaved(ctx context.Context, principal, id string) error
- func (s *Service) ListSaved(ctx context.Context, principal string) ([]Saved, error)
- func (s *Service) MarkDirty()
- func (s *Service) Providers() []Provider
- func (s *Service) RankedNames(ctx context.Context, c Caller, q string, kind Kind) ([]string, bool, error)
- func (s *Service) Reconcile(ctx context.Context) error
- func (s *Service) RecordUse(ctx context.Context, c Caller, ref string) error
- func (s *Service) Reindex(ctx context.Context, kind Kind) error
- func (s *Service) SaveSearch(ctx context.Context, principal, name, query string) (Saved, error)
- func (s *Service) Search(ctx context.Context, c Caller, req Request) (Response, error)
- func (s *Service) Suggest(ctx context.Context, c Caller, q string) ([]Suggestion, error)
- type Span
- type Suggestion
Constants ¶
const ( DefaultMaxAge = 60 * time.Second DefaultPageSize = 20 MaxPageSize = 100 )
Defaults for the freshness policy.
Variables ¶
var Actions = []ActionDef{ {ID: "app.deploy", Title: "Deploy", Keywords: "deploy release ship redeploy", Scope: ScopeApp, Ability: abilityDeploy, Confirm: true, Href: "/apps/{name}?action=deploy", MCPTool: "deploy_app", MCPNeeds: []string{"image"}}, {ID: "app.restart", Title: "Restart", Keywords: "restart reboot bounce", Scope: ScopeApp, Ability: abilityDeploy, Confirm: true, Href: "/apps/{name}?action=restart", MCPTool: "restart_app"}, {ID: "app.logs", Title: "Open logs for", Keywords: "logs tail output", Scope: ScopeApp, Ability: abilityRead, Href: "/apps/{name}/logs", MCPTool: "get_app_logs"}, {ID: "app.rollback", Title: "Rollback", Keywords: "rollback revert previous", Scope: ScopeApp, Ability: abilityDeploy, Confirm: true, Href: "/apps/{name}/deploys?action=rollback", MCPTool: "rollback_app_to_deploy", MCPNeeds: []string{"deploy_id"}}, {ID: "app.stop", Title: "Stop", Keywords: "stop halt pause", Scope: ScopeApp, Ability: abilityDeploy, Confirm: true, Href: "/apps/{name}?action=stop"}, {ID: "app.add-domain", Title: "Add a domain to", Keywords: "add domain hostname dns", Scope: ScopeApp, Ability: abilityWrite, Href: "/apps/{name}/domains", MCPTool: "set_app_domains", MCPNeeds: []string{"domains"}}, {ID: "db.backup-now", Title: "Back up now", Keywords: "backup now snapshot dump", Scope: ScopeDatabase, Ability: abilityWriteSensitive, Confirm: true, Href: "/databases/{name}?action=backup"}, {ID: "global.new-app", Title: "Create a new app", Keywords: "new app create deploy", Scope: ScopeGlobal, Ability: abilityWrite, Href: "/apps/new"}, {ID: "global.add-node", Title: "Add a node", Keywords: "add node server enroll join", Scope: ScopeGlobal, Ability: abilityRoot, Href: "/nodes"}, }
Actions is the registry. Href may contain {name}.
var ErrInvalid = errors.New("search: invalid request")
ErrInvalid marks a rejected request.
var ErrNotFound = errors.New("search: not found")
ErrNotFound is returned for a ref the caller may not see or that is gone.
Functions ¶
This section is empty.
Types ¶
type ActionDef ¶
type ActionDef struct {
ID string
Title string
Keywords string
Scope Scope
Ability string
Confirm bool
Href string
// MCPTool is the MCP tool that performs the action; empty when none exists.
MCPTool string
// MCPNeeds are inputs the agent must supply on top of the target name.
MCPNeeds []string
}
ActionDef is one entry of the action registry. Ability and Confirm mirror the route the action calls, so a hit never offers more than the API allows.
type ActionInfo ¶
type ActionInfo struct {
ID string `json:"id"`
Ability string `json:"ability"`
Confirm bool `json:"confirm"`
// MCPTool, MCPArgs and MCPNeeds say which MCP tool runs this action, with
// which arguments filled in, and which inputs the agent must still supply.
MCPTool string `json:"mcp_tool,omitempty"`
MCPArgs map[string]string `json:"mcp_args,omitempty"`
MCPNeeds []string `json:"mcp_needs,omitempty"`
}
ActionInfo is what a client needs to run an action hit.
type ActionsProvider ¶
type ActionsProvider struct {
AppNames func(ctx context.Context) ([]string, error)
DatabaseNames func(ctx context.Context) ([]string, error)
}
ActionsProvider emits the registry once per target resource.
type Authorizer ¶
Authorizer answers whether the caller may see a resource with an ability. The API layer implements it with the same engine the path routes use.
type Caller ¶
type Caller struct {
PrincipalID string
Authz Authorizer
}
Caller is who is searching.
type DB ¶
type DB interface {
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
}
DB is the slice of *sql.DB the service uses.
type Doc ¶
type Doc struct {
Ref string
Kind Kind
Title string
Body string
Tags []string
App string
Env string
Node string
Prefix string
Name string
Ability string
Confirm bool
Href string
ActionID string
UpdatedAt time.Time
}
Doc is one indexed thing. Prefix and Name name the resource whose visibility decides whether the doc may be returned, Ability is what the caller must hold on it.
type Hit ¶
type Hit struct {
Ref string `json:"ref"`
Kind Kind `json:"kind"`
Title string `json:"title"`
Subtitle string `json:"subtitle,omitempty"`
AppName string `json:"app_name,omitempty"`
Env string `json:"env,omitempty"`
NodeName string `json:"node_name,omitempty"`
Tags []string `json:"tags,omitempty"`
Href string `json:"href,omitempty"`
TitleSpans []Span `json:"title_spans,omitempty"`
Score float64 `json:"score"`
Action *ActionInfo `json:"action,omitempty"`
}
Hit is one search result.
type Kind ¶
type Kind string
Kind is the category of a search document.
const ( KindApp Kind = "app" KindDatabase Kind = "database" KindNode Kind = "node" KindDomain Kind = "domain" KindTemplate Kind = "template" KindProject Kind = "project" KindEnv Kind = "environment" KindTag Kind = "tag" KindDeployment Kind = "deployment" KindSetting Kind = "setting" KindDoc Kind = "doc" KindAction Kind = "action" KindSaved Kind = "saved" )
Document kinds.
type Query ¶
Query is a parsed search string: scoped filters plus free text.
func ParseQuery ¶
ParseQuery splits `app:foo env:prod kind:db restart api` into scopes and free text. An unknown `key:value` stays free text, so URLs and image names remain searchable.
type Response ¶
type Response struct {
Hits []Hit `json:"hits"`
NextCursor string `json:"next_cursor,omitempty"`
Total int `json:"total"`
}
Response is a page of authorized hits.
type Saved ¶
type Saved struct {
ID string `json:"id"`
Name string `json:"name"`
Query string `json:"query"`
CreatedAt time.Time `json:"created_at"`
}
Saved is a stored query of one principal.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service owns the index and answers queries.
func (*Service) DeleteSaved ¶
DeleteSaved removes one of the principal's saved searches.
func (*Service) MarkDirty ¶
func (s *Service) MarkDirty()
MarkDirty records that a store changed; the next query reconciles.
func (*Service) RankedNames ¶
func (s *Service) RankedNames(ctx context.Context, c Caller, q string, kind Kind) ([]string, bool, error)
RankedNames returns the names of every authorized doc of kind matching q in rank order, and false when the index has never been built. It filters through the same Authorizer as Search.
func (*Service) RecordUse ¶
RecordUse bumps the caller's frequency for a hit they opened. A ref the caller may not see is reported as not found.
func (*Service) SaveSearch ¶
SaveSearch stores or replaces a named query for the principal.
type Suggestion ¶
type Suggestion struct {
Text string `json:"text"`
Kind string `json:"kind"`
Ref string `json:"ref,omitempty"`
}
Suggestion is one autocomplete entry.