connectors

package
v0.4.2 Latest Latest
Warning

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

Go to latest
Published: May 2, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package connectors is the central registry for every connector definition wick will expose via MCP. Downstream apps append to it via app.RegisterConnector; the MCP and admin-UI layers walk All() at boot to validate definitions and seed default instances.

Shape of a connector module (see internal/docs/connectors-design.md for the full design):

  1. Package under internal/connectors/<name>/ exposing a Meta builder, a typed Creds struct (`wick:"..."` tags), a typed Input struct, and an `Execute(c *connector.Ctx) (any, error)` function.
  2. Register here inside RegisterBuiltins() (core wick lab) or in the downstream project's main.go via app.RegisterConnector.

Connector definitions live in code; per-instance rows (credentials, labels, tags) live in the connector_instances table — populated by the admin UI in a later phase.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func All

func All() []connector.Module

All returns every registered connector definition in registration order.

func Register

func Register(m connector.Module)

Register appends a fully-resolved Module record to the registry. Called from app.RegisterConnector; do not call directly from app code.

func RegisterBuiltins

func RegisterBuiltins()

RegisterBuiltins appends wick's own in-house connectors to the registry. Intended for the wick lab binary (cmd/lab); downstream projects start with an empty registry and register only their own connectors.

Types

type ExecuteParams

type ExecuteParams struct {
	ConnectorID  string
	OperationKey string
	Input        map[string]string
	Source       entity.ConnectorRunSource
	UserID       string
	IPAddress    string
	UserAgent    string
	// ParentRunID is set when this call replays an earlier run.
	// Intended for use with Source == ConnectorRunSourceRetry.
	ParentRunID *string
	// Progress, when non-nil, receives incremental progress events the
	// connector emits via Ctx.ReportProgress. The MCP SSE handler wires
	// a reporter that frames each event as a notifications/progress
	// JSON-RPC message; the JSON transport leaves this nil so events
	// are dropped harmlessly.
	Progress connector.ProgressReporter
}

ExecuteParams bundles the ambient context for one execution. Keeping it as a struct keeps the call site readable when more fields are added (e.g. retry parent, MCP session id).

type ExecuteResult

type ExecuteResult struct {
	RunID        string
	Status       entity.ConnectorRunStatus
	ResponseJSON string
	ErrorMessage string
	LatencyMs    int
}

ExecuteResult carries the outcome of one Execute call. Returned alongside an error so the caller (panel-test or MCP) can render the run details even when the operation itself failed.

type Repo

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

Repo wraps the gorm handle and exposes the connector-specific CRUD surface used by the admin UI, the MCP dispatch layer, and the run-history retention job.

All queries scope on context, so cancellation from the HTTP handler (or the cron worker) propagates cleanly into the DB driver.

func NewRepo

func NewRepo(db *gorm.DB) *Repo

NewRepo wires a Repo around an existing gorm handle.

func (*Repo) CountByKey

func (r *Repo) CountByKey(ctx context.Context, key string) (int64, error)

CountByKey returns how many Connector rows exist for a code key. Used by Bootstrap to decide whether to auto-create the initial row.

func (*Repo) CountRunsFiltered

func (r *Repo) CountRunsFiltered(ctx context.Context, connectorID string, f RunFilter) (int64, error)

CountRunsFiltered returns the total row count matching the same filter as ListRunsFiltered. Used to drive pagination controls.

func (*Repo) Create

func (r *Repo) Create(ctx context.Context, c *entity.Connector) error

Create inserts a new Connector row. The BeforeCreate hook on the entity stamps an ID if the caller left it empty.

func (*Repo) CreateRun

func (r *Repo) CreateRun(ctx context.Context, run *entity.ConnectorRun) error

CreateRun inserts a row at the start of an execution. Status should be ConnectorRunStatusRunning; FinishRun finalizes it.

func (*Repo) Delete

func (r *Repo) Delete(ctx context.Context, id string) error

Delete hard-deletes a connector row plus its operation toggles. Run history is intentionally preserved — deleting a connector should not retroactively erase the audit trail. The retention job purges old runs on its own cadence.

func (*Repo) FinishRun

func (r *Repo) FinishRun(ctx context.Context, runID string, status entity.ConnectorRunStatus, response, errMsg string, latencyMs, httpStatus int) error

FinishRun stamps terminal status, the response body, error message, and the timing/HTTP-status metrics. EndedAt is set to now.

func (*Repo) Get

func (r *Repo) Get(ctx context.Context, id string) (*entity.Connector, error)

Get loads a Connector by ID. Returns gorm.ErrRecordNotFound when no row matches.

func (*Repo) GetRun

func (r *Repo) GetRun(ctx context.Context, runID string) (*entity.ConnectorRun, error)

GetRun loads a single run, used by the retry handler to replay the stored RequestJSON against the current Connector.Configs.

func (*Repo) IsAccessibleForManager

func (r *Repo) IsAccessibleForManager(ctx context.Context, connectorID string, userTagIDs []string) (bool, error)

IsAccessibleForManager mirrors IsAccessibleTo but ignores the disabled flag. Used by manager handlers so admins who disabled a row can still open its detail page to re-enable.

func (*Repo) IsAccessibleTo

func (r *Repo) IsAccessibleTo(ctx context.Context, connectorID string, userTagIDs []string) (bool, error)

IsAccessibleTo reports whether a single connector row is visible to the caller using the same rule as ListAccessibleTo. Used by tools/call to re-check authorization before dispatch (the tools/list snapshot the client cached may be stale).

func (*Repo) List

func (r *Repo) List(ctx context.Context) ([]entity.Connector, error)

List returns every Connector row, newest first. Admin view.

func (*Repo) ListAccessibleForManager

func (r *Repo) ListAccessibleForManager(ctx context.Context, userTagIDs []string) ([]entity.Connector, error)

ListAccessibleForManager mirrors ListAccessibleTo but does NOT strip disabled rows. The admin manager surface must be able to enumerate disabled rows so they can be re-enabled. Tag-filter logic is unchanged.

func (*Repo) ListAccessibleTo

func (r *Repo) ListAccessibleTo(ctx context.Context, userTagIDs []string) ([]entity.Connector, error)

ListAccessibleTo returns the not-disabled Connector rows the caller is allowed to see, mirroring the Tools tag-filter rule:

  • row with no filter-type tags → visible to everyone
  • row with ≥1 filter-type tag → visible only when userTagIDs intersects the row's filter-tags

Tag association reuses the `tool_tags` table with `tool_path = '/connectors/{id}'` (see entity.Connector godoc).

Pass an empty userTagIDs for users that carry no filter tags — they still see fully untagged rows. Admin callers should bypass this and use List instead.

func (*Repo) ListByKey

func (r *Repo) ListByKey(ctx context.Context, key string) ([]entity.Connector, error)

ListByKey returns every Connector that instantiates the given code definition (e.g. all "loki" rows).

func (*Repo) ListOperations

func (r *Repo) ListOperations(ctx context.Context, connectorID string) ([]entity.ConnectorOperation, error)

ListOperations returns the toggle rows for a connector. Missing rows mean "use the per-op default" (Destructive=false → on, Destructive=true → off); callers fold the defaults in themselves.

func (*Repo) ListRunsByConnector

func (r *Repo) ListRunsByConnector(ctx context.Context, connectorID string, limit int) ([]entity.ConnectorRun, error)

ListRunsByConnector returns the most recent runs for one connector, newest first. Backed by composite index (connector_id, started_at).

func (*Repo) ListRunsFiltered

func (r *Repo) ListRunsFiltered(ctx context.Context, connectorID string, f RunFilter, limit, offset int) ([]entity.ConnectorRun, error)

ListRunsFiltered returns runs for one connector filtered by op/source/ status/user. The history page uses this to power its filter bar. Supports limit+offset for page-based paging.

func (*Repo) PurgeRunsOlderThan

func (r *Repo) PurgeRunsOlderThan(ctx context.Context, cutoff time.Time) (int64, error)

PurgeRunsOlderThan deletes ConnectorRun rows whose StartedAt is before the cutoff. Returns how many rows were removed so the retention job can log progress.

Backed by the standalone started_at index — a single range delete, no composite index needed.

func (*Repo) SetDisabled

func (r *Repo) SetDisabled(ctx context.Context, id string, disabled bool) error

SetDisabled flips the Disabled flag without touching anything else. Used by the admin manager toggle.

func (*Repo) SetOperation

func (r *Repo) SetOperation(ctx context.Context, connectorID, opKey string, enabled bool) error

SetOperation upserts the toggle for a single (connector, op) pair. Insert when no row exists, update when it does.

func (*Repo) Update

func (r *Repo) Update(ctx context.Context, c *entity.Connector) error

Update writes label / configs / disabled changes to an existing row. Identity fields (ID, Key, ParentID, CreatedBy, CreatedAt) are untouched.

type RunFilter

type RunFilter struct {
	OperationKey string
	Source       string
	Status       string
	UserID       string
}

RunFilter narrows ListRunsFiltered. Empty fields are ignored.

type Service

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

Service is the runtime façade between code-side connector definitions (kept in-memory by the registry) and DB-side connector rows. The admin UI, the panel-test handler, and the future MCP dispatcher all go through it.

Unlike the jobs Service, Bootstrap does NOT seed DB rows from code: connector instances are admin-created on demand. Bootstrap only wires the dispatch table so Execute can find the right ExecuteFunc when a row references its definition by Key.

func NewService

func NewService(r *Repo) *Service

NewService wires a Service around an existing Repo and the default HTTP client. The HTTP client is the one Ctx.HTTP exposes to every ExecuteFunc — replace with a custom client at construction time when tests need a transport hook.

func NewServiceFromDB

func NewServiceFromDB(db *gorm.DB) *Service

NewServiceFromDB is a convenience constructor for the web server and worker — both already hold a *gorm.DB.

func (*Service) Bootstrap

func (s *Service) Bootstrap(ctx context.Context, mods []connector.Module) error

Bootstrap registers code-side connector definitions for dispatch and ensures every registered Key has at least one row in the database. Call once at startup with the All() slice from the registry.

For each module: if zero rows currently exist for the Key, an empty row is auto-created with Label = Meta.Name and Configs = "{}". This makes a fresh deploy ready to use — the admin opens the UI and only has to fill in the credentials. Existing rows (and their cred edits) are NEVER touched, so an admin who has already filled cred won't see the row reset on restart.

Duplicate Keys are an error — one Key may not back two definitions. DB rows whose Key has no registered module are tolerated: they show up as "deactivated" in the admin UI, and Execute on them returns an error.

func (*Service) CountRunsFiltered

func (s *Service) CountRunsFiltered(ctx context.Context, connectorID string, f RunFilter) (int64, error)

CountRunsFiltered returns total runs matching the filter — companion of ListRunsFiltered for paging.

func (*Service) Create

func (s *Service) Create(ctx context.Context, key, label string, configs map[string]string, createdBy string) (*entity.Connector, error)

Create inserts a new Connector row for the given code-defined Key. configs is the credential map keyed by the Creds-struct field names the connector declared; it is JSON-encoded into the row.

Returns the freshly stored row (with ID stamped).

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, id string) error

Delete hard-deletes the connector row plus its operation toggles. Run history is intentionally preserved for audit.

func (*Service) Duplicate

func (s *Service) Duplicate(ctx context.Context, sourceID, createdBy string) (*entity.Connector, error)

Duplicate copies an existing connector row with credentials reset. The new row carries the same Key (so it dispatches to the same code definition) and a "(copy)"-suffixed Label; Configs is "{}" so the admin must re-fill secrets. Tag inheritance is intentionally NOT performed — the caller is responsible for assigning the creator's own tags via the existing ToolTag system.

func (*Service) Execute

func (s *Service) Execute(ctx context.Context, p ExecuteParams) (*ExecuteResult, error)

Execute runs one operation against one connector row, logging a ConnectorRun with the request, response, latency, and IP/UA.

The same code path serves panel-test, MCP tools/call, and retry — the caller distinguishes via params.Source so the run row is tagged correctly. On success the returned ResponseJSON is the marshaled ExecuteFunc return value; on error ErrorMessage carries the message (the run row also stores it).

Validation order:

  1. connector row exists and is not Disabled
  2. connector's Key has a registered module (post-Bootstrap)
  3. requested OperationKey exists on the module
  4. operation is currently Enabled (per OperationStates)

func (*Service) Get

func (s *Service) Get(ctx context.Context, id string) (*entity.Connector, error)

Get is a thin pass-through to the repo.

func (*Service) GetRun

func (s *Service) GetRun(ctx context.Context, runID string) (*entity.ConnectorRun, error)

GetRun loads a single ConnectorRun by ID. Backs the test page's prefill flow when a Retry link is followed from the history view.

func (*Service) IsManageableBy

func (s *Service) IsManageableBy(ctx context.Context, connectorID string, userTagIDs []string, isAdmin bool) (bool, error)

IsManageableBy reports whether the caller may operate on a row from the manager UI. Disabled rows are still manageable — the caller may be re-enabling them.

func (*Service) IsVisibleTo

func (s *Service) IsVisibleTo(ctx context.Context, connectorID string, userTagIDs []string, isAdmin bool) (bool, error)

IsVisibleTo reports whether a single connector row is accessible to the caller. Used by tools/call to re-check authorization at dispatch time so a stale tools/list snapshot can't be replayed for access.

func (*Service) List

func (s *Service) List(ctx context.Context) ([]entity.Connector, error)

List returns every connector row newest first, regardless of tag filter or visibility. Used by the admin manager and the retention dashboard. UI-layer code is responsible for tag-filtering for non-admin views.

func (*Service) ListForManager

func (s *Service) ListForManager(ctx context.Context, userTagIDs []string, isAdmin bool) ([]entity.Connector, error)

ListForManager returns rows the caller can see in the admin manager. Unlike ListVisibleTo, disabled rows are included so users can re- enable or delete them. Admins see every row.

func (*Service) ListRuns

func (s *Service) ListRuns(ctx context.Context, connectorID string, limit int) ([]entity.ConnectorRun, error)

ListRuns returns the most recent ConnectorRun rows for a connector, newest first. Used by the admin detail page to render history under the test panel.

func (*Service) ListRunsFiltered

func (s *Service) ListRunsFiltered(ctx context.Context, connectorID string, f RunFilter, limit, offset int) ([]entity.ConnectorRun, error)

ListRunsFiltered returns runs filtered by op / source / status / user. Backs the history page; pass zero-value filter for "no filter".

func (*Service) ListVisibleTo

func (s *Service) ListVisibleTo(ctx context.Context, userTagIDs []string, isAdmin bool) ([]entity.Connector, error)

ListVisibleTo returns the not-disabled connector rows the caller can access, applying the same tag-filter rule as Tools (see Repo.ListAccessibleTo). Pass isAdmin=true to bypass tag filtering — admins see every row whether or not they carry the row's tags.

Use this from MCP tools/list and any user-facing surface that enumerates connectors; only the admin manager should call List.

func (*Service) Module

func (s *Service) Module(key string) (connector.Module, bool)

Module looks up a definition by Key. The second return is false when no module is registered for the key (typical when a DB row outlives its code definition after a deploy that drops the connector).

func (*Service) Modules

func (s *Service) Modules() []connector.Module

Modules returns the registered definitions, useful for the "+ New instance" picker in the admin UI.

func (*Service) OperationStates

func (s *Service) OperationStates(ctx context.Context, connectorID, key string) (map[string]bool, error)

OperationStates returns the resolved enable state for every op the connector's definition declares: stored toggle when the row exists, otherwise the per-op default (off for Destructive, on for the rest).

Map key is OperationKey. Returned map is empty when the connector's Key has no registered module.

func (*Service) PurgeOldRuns

func (s *Service) PurgeOldRuns(ctx context.Context, retentionDays int) (int64, error)

PurgeOldRuns deletes ConnectorRun rows older than retentionDays. Returns the number of rows removed. Called by the cleanup job on a daily cadence (set up in a later phase).

func (*Service) Retry

func (s *Service) Retry(ctx context.Context, originalRunID, userID, ipAddr, userAgent string) (*ExecuteResult, error)

Retry replays an earlier run against the current Connector.Configs. The new run's ParentRunID points to the original; cred edits made since the original are honored.

func (*Service) SetDisabled

func (s *Service) SetDisabled(ctx context.Context, id string, disabled bool) error

SetDisabled toggles the row-level off-switch.

func (*Service) SetOperationEnabled

func (s *Service) SetOperationEnabled(ctx context.Context, connectorID, opKey string, enabled bool) error

SetOperationEnabled flips the per-(connector, op) toggle.

func (*Service) Update

func (s *Service) Update(ctx context.Context, id, label string, configs map[string]string, disabled bool) error

Update writes label / configs / disabled changes. Identity fields (Key, ParentID, CreatedBy, CreatedAt) are immutable and untouched.

Directories

Path Synopsis
Package crudcrud is a sample connector that wraps the crudcrud.com REST sandbox — a free, throwaway JSON store useful for demos and integration smoke tests.
Package crudcrud is a sample connector that wraps the crudcrud.com REST sandbox — a free, throwaway JSON store useful for demos and integration smoke tests.

Jump to

Keyboard shortcuts

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